From a4e20e993250022872e5f4add8fb49004f9f7dbf Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Wed, 21 Apr 2010 14:29:31 +0300 Subject: Implemented EXT-6783(normal sub task) - Implement saving of unread notifications. Utilized old save and load notification code. Main concern was with notifications that have complex responder - UserGiveItem, ObjectGiveItem. Those responders are object with own fields that need to persist through sessions. Notifications that should be saved are marked with persist="true" in notifications.xml Notifications using functor responders are saved automatically. Notifications using object responders need additional tuning. Responder object should be a) serializable(implement LLNotificationResponderInterface), b) registered with LLResponderRegistry. At this point following notifications persist through sessions: UserGiveItem, ObjectGiveItem, TeleportOffered, FrienshipOffered. Reviewed by Mike Antipov - https://codereview.productengine.com/secondlife/r/211/ --HG-- branch : notifications --- indra/llui/llnotifications.cpp | 158 ++++++++++++----------------------------- indra/llui/llnotifications.h | 35 +++++++-- 2 files changed, 77 insertions(+), 116 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 65ef53443b..7b8f51ae3c 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -48,122 +48,38 @@ const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; -// local channel for notification history -class LLNotificationHistoryChannel : public LLNotificationChannel +// Local channel for persistent notifications +// Stores only persistent notifications. +// Class users can use connectChanged() to process persistent notifications +// (see LLNotificationStorage for example). +class LLPersistentNotificationChannel : public LLNotificationChannel { - LOG_CLASS(LLNotificationHistoryChannel); + LOG_CLASS(LLPersistentNotificationChannel); public: - LLNotificationHistoryChannel(const std::string& filename) : - LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()), - mFileName(filename) + LLPersistentNotificationChannel() : + LLNotificationChannel("Persistent", "Visible", ¬ificationFilter, LLNotificationComparators::orderByUUID()) { - connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1)); - loadPersistentNotifications(); } private: - bool historyHandler(const LLSD& payload) - { - // we ignore "load" messages, but rewrite the persistence file on any other - std::string sigtype = payload["sigtype"]; - if (sigtype != "load") - { - savePersistentNotifications(); - } - return false; - } - - // The history channel gets all notifications except those that have been cancelled - static bool historyFilter(LLNotificationPtr pNotification) - { - return !pNotification->isCancelled(); - } - void savePersistentNotifications() + // The channel gets all persistent notifications except those that have been canceled + static bool notificationFilter(LLNotificationPtr pNotification) { - /* NOTE: As of 2009-11-09 the reload of notifications on startup does not - work, and has not worked for months. Skip saving notifications until the - read can be fixed, because this hits the disk once per notification and - causes log spam. James - - llinfos << "Saving open notifications to " << mFileName << llendl; + bool handle_notification = false; - llofstream notify_file(mFileName.c_str()); - if (!notify_file.is_open()) - { - llwarns << "Failed to open " << mFileName << llendl; - return; - } - - LLSD output; - output["version"] = NOTIFICATION_PERSIST_VERSION; - LLSD& data = output["data"]; - - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - if (!LLNotifications::instance().templateExists((*it)->getName())) continue; + handle_notification = pNotification->isPersistent() + && !pNotification->isCancelled(); - // only store notifications flagged as persisting - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName()); - if (!templatep->mPersist) continue; - - data.append((*it)->asLLSD()); - } - - LLPointer formatter = new LLSDXMLFormatter(); - formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY); - */ + return handle_notification; } - void loadPersistentNotifications() - { - llinfos << "Loading open notifications from " << mFileName << llendl; - - llifstream notify_file(mFileName.c_str()); - if (!notify_file.is_open()) - { - llwarns << "Failed to open " << mFileName << llendl; - return; - } - - LLSD input; - LLPointer parser = new LLSDXMLParser(); - if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) - { - llwarns << "Failed to parse open notifications" << llendl; - return; - } - - if (input.isUndefined()) return; - std::string version = input["version"]; - if (version != NOTIFICATION_PERSIST_VERSION) - { - llwarns << "Bad open notifications version: " << version << llendl; - return; - } - LLSD& data = input["data"]; - if (data.isUndefined()) return; - - LLNotifications& instance = LLNotifications::instance(); - for (LLSD::array_const_iterator notification_it = data.beginArray(); - notification_it != data.endArray(); - ++notification_it) - { - instance.add(LLNotificationPtr(new LLNotification(*notification_it))); - } - } - - //virtual void onDelete(LLNotificationPtr pNotification) { - // we want to keep deleted notifications in our log + // we want to keep deleted notifications in our log, otherwise some + // notifications will be lost on exit. mItems.insert(pNotification); - - return; } - -private: - std::string mFileName; }; bool filterIgnoredNotifications(LLNotificationPtr notification) @@ -417,6 +333,10 @@ LLNotification::LLNotification(const LLNotification::Params& p) : mTemporaryResponder = true; } + else if(p.functor.responder.isChosen()) + { + mResponder = p.functor.responder; + } if(p.responder.isProvided()) { @@ -462,6 +382,12 @@ LLSD LLNotification::asLLSD() output["priority"] = (S32)mPriority; output["responseFunctor"] = mResponseFunctorName; output["reusable"] = mIsReusable; + + if(mResponder) + { + output["responder"] = mResponder->asLLSD(); + } + return output; } @@ -571,12 +497,20 @@ void LLNotification::respond(const LLSD& response) // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() mRespondedTo = true; mResponse = response; - // look up the functor - LLNotificationFunctorRegistry::ResponseFunctor functor = - LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); - // and then call it - functor(asLLSD(), response); - + + if(mResponder) + { + mResponder->handleRespond(asLLSD(), response); + } + else + { + // look up the functor + LLNotificationFunctorRegistry::ResponseFunctor functor = + LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); + // and then call it + functor(asLLSD(), response); + } + if (mTemporaryResponder && !isReusable()) { LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); @@ -621,6 +555,11 @@ void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::Res LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); } +void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder) +{ + mResponder = responder; +} + bool LLNotification::payloadContainsAll(const std::vector& required_fields) const { for(std::vector::const_iterator required_fields_it = required_fields.begin(); @@ -1116,12 +1055,9 @@ void LLNotifications::createDefaultChannels() LLNotificationChannel::buildChannel("Visible", "Ignore", &LLNotificationFilters::includeEverything); - // create special history channel - //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" ); - // use ^^^ when done debugging notifications serialization - std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" ); + // create special persistent notification channel // this isn't a leak, don't worry about the empty "new" - new LLNotificationHistoryChannel(notifications_log_file); + new LLPersistentNotificationChannel(); // connect action methods to these channels LLNotifications::instance().getChannel("Expiration")-> diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1799ca65b7..c942a32512 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -116,8 +116,23 @@ typedef enum e_notification_priority NOTIFICATION_PRIORITY_CRITICAL } ENotificationPriority; +class LLNotificationResponderInterface +{ +public: + LLNotificationResponderInterface(){}; + virtual ~LLNotificationResponderInterface(){}; + + virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0; + + virtual LLSD asLLSD() = 0; + + virtual void fromLLSD(const LLSD& params) = 0; +}; + typedef boost::function LLNotificationResponder; +typedef boost::shared_ptr LLNotificationResponderPtr; + typedef LLFunctorRegistry LLNotificationFunctorRegistry; typedef LLFunctorRegistration LLNotificationFunctorRegistration; @@ -303,10 +318,12 @@ public: { Alternative name; Alternative function; + Alternative responder; Functor() : name("functor_name"), - function("functor") + function("functor"), + responder("responder") {} }; Optional functor; @@ -349,12 +366,13 @@ private: bool mIgnored; ENotificationPriority mPriority; LLNotificationFormPtr mForm; - void* mResponderObj; + void* mResponderObj; // TODO - refactor/remove this field bool mIsReusable; - + LLNotificationResponderPtr mResponder; + // a reference to the template LLNotificationTemplatePtr mTemplatep; - + /* We want to be able to store and reload notifications so that they can survive a shutdown/restart of the client. So we can't simply pass in callbacks; @@ -393,6 +411,8 @@ public: void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); + void setResponseFunctor(const LLNotificationResponderPtr& responder); + typedef enum e_response_template_type { WITHOUT_DEFAULT_BUTTON, @@ -459,7 +479,12 @@ public: { return mTemplatep->mName; } - + + bool isPersistent() const + { + return mTemplatep->mPersist; + } + const LLUUID& id() const { return mId; -- cgit v1.3 From 2ce7556e53544e50a4d4d28705976655cafa6992 Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Wed, 21 Apr 2010 15:44:24 +0300 Subject: Implemented by SL EXT-6722(normal task) - Create modified inventory view for "my outfits" tab in top-level appearance sidebar (tier 1) llui: - Setting container panel for accordion tab control to dynamically add tabs to accordions. - Added method to dynamically remove accordion tabs. - Added LLIconCtrl image setter. newview: - Class LLOutfitsList - a list of agents's outfits from "My Outfits" inventory category which represents each outfit by an accordion tab with a list of items inside it. - Class LLWearableItemsList - a list of wearable items used in each accordion tab of "My Outfits" tab. - Class LLInventoryItemsList - a base class for LLWearableItemsList that represents inventory items by panels in LLFlatListView. - Class LLPanelInventoryItem - inventory item representation for a flat list. Item icon is set according to item type. - Class LLInventoryCategoriesObserver - an observer used in LLOutfitsList for monitoring changes to "My Outfits" inventory category and updating outfits accordion tabs and list of items for each outfit. Known issues: - Only first outfit tab is displayed in "My Outfits" until this tab is expanded. - Bottom bar buttons and filter field not functioning for "My Outfits" tab since LLOutfitsList still doesn't support selection, filtering and sorting. - "My Outfits" and "Wearing" tabs of "Appearance" side panel might need a common interface to use LLOutfitsList and LLinventoryPanel as tabs in LLPanelOutfitsInventory or "Wearing" tab should be replaces with LLOutfitsList class object i.e. a flat list. On review - https://codereview.productengine.com/secondlife/r/285/ --HG-- branch : product-engine --- indra/llui/llaccordionctrl.cpp | 22 +- indra/llui/llaccordionctrl.h | 1 + indra/llui/llaccordionctrltab.cpp | 3 + indra/llui/lliconctrl.h | 1 + indra/newview/CMakeLists.txt | 6 + indra/newview/llagentwearables.cpp | 3 +- indra/newview/llinventoryitemslist.cpp | 141 +++++++++++ indra/newview/llinventoryitemslist.h | 88 +++++++ indra/newview/llinventoryobserver.cpp | 32 +++ indra/newview/llinventoryobserver.h | 37 ++- indra/newview/lloutfitslist.cpp | 265 +++++++++++++++++++++ indra/newview/lloutfitslist.h | 74 ++++++ indra/newview/llpaneloutfitsinventory.cpp | 141 ++++++----- indra/newview/llpaneloutfitsinventory.h | 16 +- indra/newview/llsidepanelappearance.cpp | 4 +- indra/newview/llwearableitemslist.cpp | 88 +++++++ indra/newview/llwearableitemslist.h | 56 +++++ .../skins/default/xui/en/panel_inventory_item.xml | 51 ++++ .../default/xui/en/panel_outfits_inventory.xml | 20 +- .../skins/default/xui/en/panel_outfits_list.xml | 25 ++ 20 files changed, 988 insertions(+), 86 deletions(-) create mode 100644 indra/newview/llinventoryitemslist.cpp create mode 100644 indra/newview/llinventoryitemslist.h create mode 100644 indra/newview/lloutfitslist.cpp create mode 100644 indra/newview/lloutfitslist.h create mode 100644 indra/newview/llwearableitemslist.cpp create mode 100644 indra/newview/llwearableitemslist.h create mode 100644 indra/newview/skins/default/xui/en/panel_inventory_item.xml create mode 100644 indra/newview/skins/default/xui/en/panel_outfits_list.xml (limited to 'indra/llui') 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(view); + if(!accordion_tab) + return; + + if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) != getChildList()->end()) + removeChild(accordion_tab); + + for (std::vector::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/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 image) { mImagep = image; } private: void setIconImageDrawSize() ; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index efb16d1e42..99ee1835fc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -252,6 +252,7 @@ set(viewer_SOURCE_FILES llinventoryclipboard.cpp llinventoryfilter.cpp llinventoryfunctions.cpp + llinventoryitemslist.cpp llinventorymodel.cpp llinventorymodelbackgroundfetch.cpp llinventoryobserver.cpp @@ -295,6 +296,7 @@ set(viewer_SOURCE_FILES llnotificationofferhandler.cpp llnotificationscripthandler.cpp llnotificationtiphandler.cpp + lloutfitslist.cpp lloutputmonitorctrl.cpp llpanelavatar.cpp llpanelavatartag.cpp @@ -528,6 +530,7 @@ set(viewer_SOURCE_FILES llwaterparamset.cpp llwearable.cpp llwearabledictionary.cpp + llwearableitemslist.cpp llwearablelist.cpp llweb.cpp llwind.cpp @@ -756,6 +759,7 @@ set(viewer_HEADER_FILES llinventoryclipboard.h llinventoryfilter.h llinventoryfunctions.h + llinventoryitemslist.h llinventorymodel.h llinventorymodelbackgroundfetch.h llinventoryobserver.h @@ -795,6 +799,7 @@ set(viewer_HEADER_FILES llnetmap.h llnotificationhandler.h llnotificationmanager.h + lloutfitslist.h lloutputmonitorctrl.h llpanelavatar.h llpanelavatartag.h @@ -1030,6 +1035,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 7a088fc7bf..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(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); diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp new file mode 100644 index 0000000000..9489e0f2e4 --- /dev/null +++ b/indra/newview/llinventoryitemslist.cpp @@ -0,0 +1,141 @@ +/** + * @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" + +#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("item_icon"); + mTitle = getChild("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) +{} + +// virtual +LLInventoryItemsList::~LLInventoryItemsList() +{} + +void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array) +{ + clear(); + + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *item = (*iter); + + LLPanelInventoryItem *list_item = new LLPanelInventoryItem(item->getType(), + item->getInventoryType(), + item->getFlags(), + item->getName(), + LLStringUtil::null); + if (!addItem(list_item, item->getUUID())) + { + llerrs << "Couldn't add flat item." << llendl; + } + } +} diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h new file mode 100644 index 0000000000..bba739dbbf --- /dev/null +++ b/indra/newview/llinventoryitemslist.h @@ -0,0 +1,88 @@ +/** + * @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); + +protected: + friend class LLUICtrlFactory; + LLInventoryItemsList(const LLFlatListView::Params& p); +}; + +#endif //LL_LLINVENTORYITEMSLIST_H diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 544a815896..5aee84ce29 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -647,3 +647,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 c48ffaa55d..627decc915 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -262,5 +262,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 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 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/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 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("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(params); + + mAccordion->addCollapsibleCtrl(tab); + + LLFlatListView::Params list_params; + LLWearableItemsList* list = LLUICtrlFactory::create(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("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 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/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 367ce46ce6..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() @@ -267,6 +277,11 @@ void LLPanelOutfitsInventory::onSave() void LLPanelOutfitsInventory::onSelectionChange(const std::deque &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 selection_set; - root->getSelectionList(selection_set); - can_delete = (selection_set.size() > 0); - for (std::set::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 selection_set; + root->getSelectionList(selection_set); + can_delete = (selection_set.size() > 0); + for (std::set::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 selection_set; - root->getSelectionList(selection_set); - has_items_selected = (selection_set.size() > 0); + LLFolderView* root = getActivePanel()->getRootFolder(); + if (root) + { + std::set 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(COF_TAB_NAME); - cof_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mTabPanels.push_back(cof_panel); + mCurrentOutfitPanel = getChild(COF_TAB_NAME); + mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2)); - LLInventoryPanel *myoutfits_panel = getChild(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(OUTFITS_TAB_NAME); mAppearanceTabs = getChild("appearance_tabs"); mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this)); - mActivePanel = (LLInventoryPanel*)mAppearanceTabs->getCurrentPanel(); } void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque &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 &items, BOOL user_action); void onTabChange(); - BOOL isCOFPanelActive() const; private: - LLInventoryPanel* mActivePanel; - typedef std::vector tabpanels_vec_t; - tabpanels_vec_t mTabPanels; + LLOutfitsList* mMyOutfitsPanel; + LLInventoryPanel* mCurrentOutfitPanel; // tab panels // //////////////////////////////////////////////////////////////////////////////// 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/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 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/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 @@ + + + + + + + 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"> - + label="MY OUTFITS" + layout="topleft" + width="315" /> + + + + -- cgit v1.3 From 647327d0eca0c089d94ce964a8cc837cc2888e93 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Wed, 21 Apr 2010 20:23:55 +0300 Subject: Fixed normal bug EXT-6907 ('Show residents profile' menu opens inspector instead of profile) - added 'Url.ShowProfile' action. Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/282/ --HG-- branch : product-engine --- indra/llui/lltextbase.cpp | 1 + indra/llui/llurlaction.cpp | 17 +++++++++++++++++ indra/llui/llurlaction.h | 3 +++ indra/newview/skins/default/xui/en/menu_url_agent.xml | 2 +- indra/newview/skins/default/xui/en/menu_url_group.xml | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) (limited to 'indra/llui') 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/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"> + function="Url.ShowProfile" /> 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"> + function="Url.ShowProfile" /> -- cgit v1.3 From edd0e47d5cb3eb173da4d6710ce6a83f771a0246 Mon Sep 17 00:00:00 2001 From: Dmitry Zaporozhan Date: Thu, 22 Apr 2010 12:40:36 +0300 Subject: Fixed EXT-6597(normal) - Clicking the maturity rating icons in the navbar need tooltips and clicking should link to a help article. Added LLButton::setImagePressed(), there was no way to set pressed image at run-time. The only place where pressed image is initialized was LLButton constructor. Replaced Maturity icon with button to simplify handling clicks. Icon does not provide click callback and we would need to handle mouse up/down events and track clicked widget. Added icon for Moderate regions. Did not find maturity help topic, added a "TODO". Reviewed by Sergey Litovchuk - https://codereview.productengine.com/secondlife/r/243/ --HG-- branch : product-engine --- indra/llui/llbutton.cpp | 5 ++ indra/llui/llbutton.h | 1 + indra/newview/lllocationinputctrl.cpp | 74 ++++++++++++++++------ indra/newview/lllocationinputctrl.h | 21 +++--- indra/newview/skins/default/xui/en/strings.xml | 3 + .../default/xui/en/widgets/location_input.xml | 4 +- 6 files changed, 78 insertions(+), 30 deletions(-) (limited to 'indra/llui') 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 image) mFadeWhenDisabled = TRUE; } +void LLButton::setImagePressed(LLPointer image) +{ + mImagePressed = image; +} + void LLButton::setImageHoverSelected(LLPointer 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 image); void setImageDisabled(LLPointer image); void setImageDisabledSelected(LLPointer image); + void setImagePressed(LLPointer image); void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } 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 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(maturity_icon); - addChild(mMaturityIcon); + LLButton::Params maturity_button = p.maturity_button; + mMaturityButton = LLUICtrlFactory::create(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 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 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 maturity_help_topic; Optional icon_hpad, add_landmark_hpad; - Optional add_landmark_button, + Optional maturity_button, + add_landmark_button, for_sale_button, info_button; - Optional maturity_icon, - voice_icon, + Optional 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 mIconMaturityGeneral; + LLPointer mIconMaturityAdult; + LLPointer 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/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 91c0af118f..023aba8d7b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2897,6 +2897,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Building/dropping objects not allowed Scripts not allowed Health + Adult Region + Moderate Region + General Region 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 @@ - Date: Fri, 23 Apr 2010 07:53:56 +0300 Subject: Fixed normal EXT-6841 ([TRUNCATION] Sidebar > People. Choose and show a group > Land/ Assets. \"No tienes permiso para ver el terreno propiedad del g\") -Applied ward wrap for comments in scroll list Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/298/ --HG-- branch : product-engine --- indra/llui/llscrolllistctrl.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index db0f2bd6e2..94eade06ad 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -282,6 +282,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) text_p.border_visible(false); text_p.rect(mItemListRect); text_p.follows.flags(FOLLOWS_ALL); + // word wrap was added accroding to the EXT-6841 + text_p.wrap(true); addChild(LLUICtrlFactory::create(text_p)); } -- cgit v1.3