diff options
author | Steven Bennetts <steve@lindenlab.com> | 2009-08-28 22:58:17 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2009-08-28 22:58:17 +0000 |
commit | 0aa2bc4831674e61edf680887eba9acec9f997ed (patch) | |
tree | edf19fd9b857cf13b9e7ad943b65178954b4811c /indra | |
parent | 51500f82e23b7deff9a0e1bc23f5bfa40aec1fb9 (diff) |
svn merge -r 1490-1500 https://svn.aws.productengine.com/secondlife/pe/stable-2
Bug Fixes:
* EXT-637 EXT-595
Dev work:
* EXT-694
QA:
* Be sure feature works on other locales
Known issues:
* If old Calling Card of person who presents in the friend list is removed - "Do you want to remove ..." dialog is shown, if old Calling Card of non-friend is removed it is removed in the old way without any alerts.
* It is possible to create 2 deep level subfolders under the Calling Cards/Friends/ subfolders. This should be disabled due to Accordion does not support tree hierarchy.
* If friendship is removed when agent is offline, Friend Card is not removed from Inventory.
Diffstat (limited to 'indra')
36 files changed, 844 insertions, 157 deletions
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 4edae46f32..d6dfe6c198 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1642,6 +1642,7 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p) mHorizontalLayout( p.horizontal_layout ), mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout mMaxScrollableItems(p.max_scrollable_items), + mPreferredWidth(p.preferred_width), mKeepFixedSize( p.keep_fixed_size ), mLabel (p.label), mLastMouseX(0), @@ -2025,6 +2026,9 @@ void LLMenuGL::arrange( void ) } } + if (mPreferredWidth < U32_MAX) + width = llmin(mPreferredWidth, max_width); + if (mScrollable) { S32 max_items_height = max_height - spillover_item_height * 2; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 44459a6c0e..0bf6301f93 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -383,6 +383,7 @@ public: keep_fixed_size, scrollable; Optional<U32> max_scrollable_items; + Optional<U32> preferred_width; Optional<LLUIColor> bg_color; Optional<S32> shortcut_pad; @@ -396,7 +397,9 @@ public: bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), scrollable("scrollable", false), max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), shortcut_pad("shortcut_pad") + { addSynonym(bg_visible, "opaque"); addSynonym(bg_color, "color"); @@ -544,6 +547,7 @@ protected: S32 mMouseVelX; S32 mMouseVelY; U32 mMaxScrollableItems; + U32 mPreferredWidth; BOOL mHorizontalLayout; BOOL mScrollable; BOOL mKeepFixedSize; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 43d5f70b2f..9878a71d89 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -213,6 +213,7 @@ set(viewer_SOURCE_FILES llfolderview.cpp llfolderviewitem.cpp llfollowcam.cpp + llfriendcard.cpp llgesturemgr.cpp llgivemoney.cpp llglsandbox.cpp @@ -668,6 +669,7 @@ set(viewer_HEADER_FILES llfoldervieweventlistener.h llfolderviewitem.h llfollowcam.h + llfriendcard.h llgesturemgr.h llgivemoney.h llgroupactions.h diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 4e289efd1b..5f71b6e3f6 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -42,7 +42,7 @@ #include "llagent.h" #include "llappviewer.h" // for gLastVersionChannel #include "llcallingcard.h" // for LLAvatarTracker -#include "llinventorymodel.h" +#include "llinventorymodel.h" // for gInventory.findCategoryUUIDForType #include "llimview.h" // for gIMMgr #include "llsidetray.h" #include "llviewermessage.h" // for handle_lure @@ -229,8 +229,6 @@ bool LLAvatarActions::handleRemove(const LLSD& notification, const LLSD& respons } LLAvatarTracker::instance().terminateBuddy(id); LLAvatarTracker::instance().notifyObservers(); - gInventory.addChangedMask(LLInventoryObserver::LABEL | LLInventoryObserver::CALLING_CARD, LLUUID::null); - gInventory.notifyObservers(); break; case 1: // NO diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 355a90209a..7326e39af3 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -95,29 +95,8 @@ const F32 OFFLINE_SECONDS = FIND_FREQUENCY + 8.0f; // static LLAvatarTracker LLAvatarTracker::sInstance; -/* -class LLAvatarTrackerInventoryObserver : public LLInventoryObserver -{ -public: - LLAvatarTrackerInventoryObserver(LLAvatarTracker* at) : - mAT(at) {} - virtual ~LLAvatarTrackerInventoryObserver() {} - virtual void changed(U32 mask); -protected: - LLAvatarTracker* mAT; -}; -*/ -/* -void LLAvatarTrackerInventoryObserver::changed(U32 mask) -{ - // if there's a calling card change, just do it. - if((mask & LLInventoryObserver::CALLING_CARD) != 0) - { - mAT->inventoryChanged(); - } -} -*/ + ///---------------------------------------------------------------------------- /// Class LLAvatarTracker @@ -329,7 +308,8 @@ void LLAvatarTracker::terminateBuddy(const LLUUID& id) msg->nextBlock("ExBlock"); msg->addUUID("OtherID", id); gAgent.sendReliableMessage(); - mModifyMask |= LLFriendObserver::REMOVE; + + addChangedMask(LLFriendObserver::REMOVE, id); delete buddy; } @@ -503,6 +483,18 @@ void LLAvatarTracker::notifyObservers() (*it)->changed(mModifyMask); } mModifyMask = LLFriendObserver::NONE; + mChangedBuddyIDs.clear(); +} + +// store flag for change +// and id of object change applies to +void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent) +{ + mModifyMask |= mask; + if (referent.notNull()) + { + mChangedBuddyIDs.insert(referent); + } } void LLAvatarTracker::applyFunctor(LLRelationshipFunctor& f) @@ -706,7 +698,7 @@ void LLAvatarTracker::formFriendship(const LLUUID& id) //visible online to each other. buddy_info = new LLRelationship(LLRelationship::GRANT_ONLINE_STATUS,LLRelationship::GRANT_ONLINE_STATUS, false); at.mBuddyInfo[id] = buddy_info; - at.mModifyMask |= LLFriendObserver::ADD; + at.addChangedMask(LLFriendObserver::ADD, id); at.notifyObservers(); } } @@ -722,7 +714,7 @@ void LLAvatarTracker::processTerminateFriendship(LLMessageSystem* msg, void**) LLRelationship* buddy = get_ptr_in_map(at.mBuddyInfo, id); if(!buddy) return; at.mBuddyInfo.erase(id); - at.mModifyMask |= LLFriendObserver::REMOVE; + at.addChangedMask(LLFriendObserver::REMOVE, id); delete buddy; at.notifyObservers(); } diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 85a1ab6e1e..113f16de70 100644 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -147,6 +147,17 @@ public: void removeObserver(LLFriendObserver* observer); void notifyObservers(); + /** + * Stores flag for change and id of object change applies to + * + * This allows outsiders to tell the AvatarTracker if something has + * been changed 'under the hood', + * and next notification will have exact avatar IDs have been changed. + */ + void addChangedMask(U32 mask, const LLUUID& referent); + + const std::set<LLUUID>& getChangedIDs() { return mChangedBuddyIDs; } + // Apply the functor to every buddy. Do not actually modify the // buddy list in the functor or bad things will happen. void applyFunctor(LLRelationshipFunctor& f); @@ -179,6 +190,9 @@ protected: buddy_map_t mBuddyInfo; + typedef std::set<LLUUID> changed_buddy_t; + changed_buddy_t mChangedBuddyIDs; + typedef std::vector<LLFriendObserver*> observer_list_t; observer_list_t mObservers; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 70ee5d395e..7ad60232c7 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -61,6 +61,55 @@ static LLDefaultChildRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar"); const S32 DROP_DOWN_MENU_WIDTH = 250; /** + * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem. + * Performing requests for SLURL for given Landmark ID + */ +class LLSLURLGetter +{ +public: + LLSLURLGetter() + : mLandmarkID(LLUUID::null) + , mSLURL("(Loading...)") + , mLoaded(false) {} + + void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + + const std::string& getSLURL() + { + if(!mLoaded) + requestSLURL(); + + return mSLURL; + } +private: + /** + * Requests landmark data from server. + */ + void requestSLURL() + { + if (mLandmarkID.isNull()) + return; + + LLVector3d g_pos; + if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) + { + LLLandmarkActions::getSLURLfromPosGlobal(g_pos, + boost::bind(&LLSLURLGetter::landmarkNameCallback, this, _1), false); + } + } + + void landmarkNameCallback(const std::string& name) + { + mSLURL = name; + mLoaded = true; + } + + LLUUID mLandmarkID; + std::string mSLURL; + bool mLoaded; +}; + +/** * This class is needed to override LLButton default handleToolTip function and * show SLURL as button tooltip. * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons @@ -71,9 +120,6 @@ class LLFavoriteLandmarkButton : public LLButton { public: - /** - * Requests landmark data from server and shows landmark SLURL as tooltip. - */ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) { if(LLUI::sShowXUINames) @@ -81,48 +127,53 @@ public: return LLButton::handleToolTip(x, y, msg, sticky_rect); } - if(!mLoaded) - { - LLVector3d g_pos; - if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) - { - LLLandmarkActions::getSLURLfromPosGlobal(g_pos, - boost::bind(&LLFavoriteLandmarkButton::landmarkNameCallback, this, _1), false); - } - } - - msg = mSLURL; + msg = mUrlGetter.getSLURL(); return TRUE; } - - void landmarkNameCallback(const std::string& name) - { - mSLURL = name; - mLoaded = true; - } - void setLandmarkID(const LLUUID& id){ mLandmarkID = id; } + void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } protected: + LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} + friend class LLUICtrlFactory; - LLFavoriteLandmarkButton(const LLButton::Params& p) - : LLButton(p) - , mLandmarkID(LLUUID::null) - , mSLURL("(Loading...)") - , mLoaded(false) +private: + LLSLURLGetter mUrlGetter; +}; + +/** + * This class is needed to override LLMenuItemCallGL default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in showDropDownMenu function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL +{ +public: + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) { - static std::string loading_tooltip = LLTrans::getString("favorite_landmark_loading_tooltip"); - mSLURL = loading_tooltip; + if(LLUI::sShowXUINames) + { + return LLMenuItemCallGL::handleToolTip(x, y, msg, sticky_rect); + } + + msg = mUrlGetter.getSLURL(); + return TRUE; } + + void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + +protected: + LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} friend class LLUICtrlFactory; private: - LLUUID mLandmarkID; - std::string mSLURL; - bool mLoaded; + LLSLURLGetter mUrlGetter; }; + // updateButtons's helper struct LLFavoritesSort { @@ -483,6 +534,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() menu_p.visible(false); menu_p.scrollable(true); menu_p.max_scrollable_items = 10; + menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; LLToggleableMenu* menu = LLUICtrlFactory::create<LLToggleableMenu>(menu_p); @@ -554,8 +606,10 @@ void LLFavoritesBarCtrl::showDropDownMenu() item_params.label(item_name); item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); - LLMenuItemCallGL *menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params); menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this,item->getUUID(),_1,_2,_3,_4)); + menu_item->setLandmarkID(item->getUUID()); + // Check whether item name wider than menu if (menu_item->getNominalWidth() > max_width) { @@ -583,7 +637,8 @@ void LLFavoritesBarCtrl::showDropDownMenu() menu->setButtonRect(mChevronRect, this); - LLMenuGL::showPopup(this, menu, getRect().getWidth() - widest_item, 0); + LLMenuGL::showPopup(this, menu, getRect().getWidth() - max_width, 0); + } } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 818381b561..4d154c4cd3 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -54,7 +54,6 @@ #include "llagent.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llfloaterinventory.h" #include "llfloaterreg.h" #include "lllineeditor.h" #include "lltexturectrl.h" diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 8961508bcc..f1e499e14b 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -231,6 +231,8 @@ void LLFolderViewItem::refreshFromListener() // *TODO: to be removed when database supports multi language. This is a // temporary attempt to display the inventory folder in the user locale. + // mantipov: *NOTE: be sure this code is synchronized with LLFriendCardsManager::findChildFolderUUID + // it uses the same way to find localized string if (LLAssetType::lookupIsProtectedCategoryType(preferred_type)) { LLTrans::findString(mLabel, "InvFolder " + mLabel); diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp new file mode 100644 index 0000000000..bef5f094e3 --- /dev/null +++ b/indra/newview/llfriendcard.cpp @@ -0,0 +1,425 @@ +/** + * @file llfriendcard.cpp + * @brief Implementation of classes to process Friends Cards + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llinventory.h" +#include "lltrans.h" + +#include "llfriendcard.h" + +#include "llcallingcard.h" // for LLAvatarTracker +#include "llviewerinventory.h" +#include "llinventorymodel.h" + +// Constants; + +static const std::string INVENTORY_STRING_FRIENDS_SUBFOLDER = "Friends"; +static const std::string INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER = "All"; + +// helper functions + +/* +mantipov *NOTE: unable to use +LLTrans::getString("InvFolder Friends"); or +LLTrans::getString("InvFolder FriendsAll"); +in next two functions to set localized folders' names because of there is a hack in the +LLFolderViewItem::refreshFromListener() method for protected asset types. +So, localized names will be got from the strings with "InvFolder LABEL_NAME" in the strings.xml +*/ +inline const std::string& get_friend_folder_name() +{ + return INVENTORY_STRING_FRIENDS_SUBFOLDER; +} + +inline const std::string& get_friend_all_subfolder_name() +{ + return INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER; +} + +void move_from_to_arrays(LLInventoryModel::cat_array_t& from, LLInventoryModel::cat_array_t& to) +{ + while (from.count() > 0) + { + to.put(from.get(0)); + from.remove(0); + } +} + +const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollectFunctor& matchFunctor) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendentsIf(parentFolderUUID, cats, items, + LLInventoryModel::EXCLUDE_TRASH, matchFunctor); + + if (cats.count() == 1) + { + return cats.get(0)->getUUID(); + } + + return LLUUID::null; +} + +// LLFriendCardsManager Constructor / Destructor +LLFriendCardsManager::LLFriendCardsManager() +{ + LLAvatarTracker::instance().addObserver(this); +} + +LLFriendCardsManager::~LLFriendCardsManager() +{ + LLAvatarTracker::instance().removeObserver(this); +} + +void LLFriendCardsManager::putAvatarData(const LLUUID& avatarID) +{ + llinfos << "Store avatar data, avatarID: " << avatarID << llendl; + std::pair< avatar_uuid_set_t::iterator, bool > pr; + pr = mBuddyIDSet.insert(avatarID); + if (pr.second == false) + { + llwarns << "Trying to add avatar UUID for the stored avatar: " + << avatarID + << llendl; + } +} + +const LLUUID LLFriendCardsManager::extractAvatarID(const LLUUID& avatarID) +{ + LLUUID rv; + avatar_uuid_set_t::iterator it = mBuddyIDSet.find(avatarID); + if (mBuddyIDSet.end() == it) + { + llwarns << "Call method for non-existent avatar name in the map: " << avatarID << llendl; + } + else + { + rv = (*it); + mBuddyIDSet.erase(it); + } + return rv; +} + +// be sure LLInventoryModel::buildParentChildMap() has been called before it. +// and this method must be called before any actions with friend list +void LLFriendCardsManager::ensureFriendFoldersExist() +{ + LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + if (friendFolderUUID.isNull()) + { + friendFolderUUID = gInventory.createNewCategory(callingCardsFolderID, + LLAssetType::AT_CALLINGCARD, get_friend_folder_name()); + } + + LLUUID friendAllSubfolderUUID = findFriendAllSubfolderUUIDImpl(); + + if (friendAllSubfolderUUID.isNull()) + { + friendAllSubfolderUUID = gInventory.createNewCategory(friendFolderUUID, + LLAssetType::AT_CALLINGCARD, get_friend_all_subfolder_name()); + } +} + + +bool LLFriendCardsManager::isItemInAnyFriendsList(const LLViewerInventoryItem* item) +{ + if (item->getType() != LLAssetType::AT_CALLINGCARD) + return false; + + LLInventoryModel::item_array_t items; + findMatchedFriendCards(item->getCreatorUUID(), items); + + return items.count() > 0; +} + +bool LLFriendCardsManager::isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const +{ + if (NULL == cat) + return false; + return TRUE == gInventory.isObjectDescendentOf(cat->getUUID(), findFriendFolderUUIDImpl()); +} + +void LLFriendCardsManager::syncFriendsFolder() +{ + //lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" if they are absent + LLFriendCardsManager::instance().ensureFriendFoldersExist(); + + LLAvatarTracker::buddy_map_t all_buddies; + LLAvatarTracker::instance().copyBuddyList(all_buddies); + + // 1. Remove Friend Cards for non-friends + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(findFriendAllSubfolderUUIDImpl(), cats, items, LLInventoryModel::EXCLUDE_TRASH); + + LLInventoryModel::item_array_t::const_iterator it; + for (it = items.begin(); it != items.end(); ++it) + { + lldebugs << "Check if buddy is in list: " << (*it)->getName() << " " << (*it)->getCreatorUUID() << llendl; + if (NULL == get_ptr_in_map(all_buddies, (*it)->getCreatorUUID())) + { + lldebugs << "NONEXISTS, so remove it" << llendl; + removeFriendCardFromInventory((*it)->getCreatorUUID()); + } + } + + // 2. Add missing Friend Cards for friends + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + llinfos << "try to build friends, count: " << all_buddies.size() << llendl; + for(; buddy_it != all_buddies.end(); ++buddy_it) + { + const LLUUID& buddy_id = (*buddy_it).first; + addFriendCardToInventory(buddy_id); + } +} + +void LLFriendCardsManager::collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const +{ + folderBuddiesMap.clear(); + + LLInventoryModel::cat_array_t* listFolders; + LLInventoryModel::item_array_t* items; + + // get folders in the Friend folder. Items should be NULL due to Cards should be in lists. + gInventory.getDirectDescendentsOf(findFriendFolderUUIDImpl(), listFolders, items); + + if (NULL == listFolders) + return; + + LLInventoryModel::cat_array_t::const_iterator itCats; // to iterate Friend Lists (categories) + LLInventoryModel::item_array_t::const_iterator itBuddy; // to iterate Buddies in each List + LLInventoryModel::cat_array_t* fakeCatsArg; + for (itCats = listFolders->begin(); itCats != listFolders->end(); ++itCats) + { + if (items) + items->clear(); + + // *HACK: Only Friends/All content will be shown for now + // *TODO: Remove this hack, implement sorting if it will be needded by spec. + if ((*itCats)->getUUID() != findFriendAllSubfolderUUIDImpl()) + continue; + + gInventory.getDirectDescendentsOf((*itCats)->getUUID(), fakeCatsArg, items); + + if (NULL == items) + continue; + + std::vector<LLUUID> buddyUUIDs; + for (itBuddy = items->begin(); itBuddy != items->end(); ++itBuddy) + { + buddyUUIDs.push_back((*itBuddy)->getCreatorUUID()); + } + + folderBuddiesMap.insert(make_pair((*itCats)->getUUID(), buddyUUIDs)); + } +} + + +/************************************************************************/ +/* Private Methods */ +/************************************************************************/ +const LLUUID& LLFriendCardsManager::findFriendFolderUUIDImpl() const +{ + LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + + std::string friendFolderName = get_friend_folder_name(); + + return findChildFolderUUID(callingCardsFolderID, friendFolderName); +} + +const LLUUID& LLFriendCardsManager::findFriendAllSubfolderUUIDImpl() const +{ + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + std::string friendAllSubfolderName = get_friend_all_subfolder_name(); + + return findChildFolderUUID(friendFolderUUID, friendAllSubfolderName); +} + +const LLUUID& LLFriendCardsManager::findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& folderLabel) const +{ + // mantipov *HACK: get localaized name in the same way like in the LLFolderViewItem::refreshFromListener() method. + // be sure these both methods are synchronized. + // see also get_friend_folder_name() and get_friend_all_subfolder_name() functions + std::string localizedName = LLTrans::getString("InvFolder " + folderLabel); + + LLNameCategoryCollector matchFolderFunctor(localizedName); + + return get_folder_uuid(parentFolderUUID, matchFolderFunctor); +} +const LLUUID& LLFriendCardsManager::findFriendCardInventoryUUIDImpl(const LLUUID& avatarID) +{ + LLUUID friendAllSubfolderUUID = findFriendAllSubfolderUUIDImpl(); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + + // it is not necessary to check friendAllSubfolderUUID against NULL. It will be processed by collectDescendents + gInventory.collectDescendents(friendAllSubfolderUUID, cats, items, LLInventoryModel::EXCLUDE_TRASH); + for (it = items.begin(); it != items.end(); ++it) + { + if ((*it)->getCreatorUUID() == avatarID) + return (*it)->getUUID(); + } + + return LLUUID::null; +} + +void LLFriendCardsManager::findMatchedFriendCards(const LLUUID& avatarID, LLInventoryModel::item_array_t& items) const +{ + LLInventoryModel::cat_array_t cats; + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + LLParticularBuddyCollector matchFunctor(avatarID); + + LLViewerInventoryCategory* friendFolder = gInventory.getCategory(friendFolderUUID); + + LLInventoryModel::cat_array_t subFolders; + subFolders.push_back(friendFolder); + + while (subFolders.count() > 0) + { + LLViewerInventoryCategory* cat = subFolders.get(0); + subFolders.remove(0); + + gInventory.collectDescendentsIf(cat->getUUID(), cats, items, + LLInventoryModel::EXCLUDE_TRASH, matchFunctor); + + move_from_to_arrays(cats, subFolders); + } +} + +class CreateFriendCardCallback : public LLInventoryCallback +{ +public: + void fire(const LLUUID& inv_item_id) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); + + if (item) + LLFriendCardsManager::instance().extractAvatarID(item->getCreatorUUID()); + } +}; + +bool LLFriendCardsManager::addFriendCardToInventory(const LLUUID& avatarID) +{ + LLInventoryModel* invModel = &gInventory; + + bool shouldBeAdded = true; + std::string name; + gCacheName->getFullName(avatarID, name); + + lldebugs << "Processing buddy name: " << name + << ", id: " << avatarID + << llendl; + + if (shouldBeAdded && findFriendCardInventoryUUIDImpl(avatarID).notNull()) + { + shouldBeAdded = false; + lldebugs << "is found in Inventory: " << name << llendl; + } + + if (shouldBeAdded && isAvatarDataStored(avatarID)) + { + shouldBeAdded = false; + lldebugs << "is found in sentRequests: " << name << llendl; + } + + LLUUID friendListFolderID = findFriendAllSubfolderUUIDImpl(); + if (shouldBeAdded && !invModel->isCategoryComplete(friendListFolderID)) + { + shouldBeAdded = false; + } + if (shouldBeAdded) + { + putAvatarData(avatarID); + lldebugs << "Sent create_inventory_item for " << avatarID << ", " << name << llendl; + + // TODO: mantipov: Is CreateFriendCardCallback really needed? Probably not + LLPointer<LLInventoryCallback> cb = new CreateFriendCardCallback(); + + create_inventory_callingcard(avatarID, friendListFolderID, cb); + } + + return shouldBeAdded; +} + +void LLFriendCardsManager::removeFriendCardFromInventory(const LLUUID& avatarID) +{ + LLInventoryModel::item_array_t items; + findMatchedFriendCards(avatarID, items); + + LLInventoryModel::item_array_t::const_iterator it; + for (it = items.begin(); it != items.end(); ++ it) + { + gInventory.removeItem((*it)->getUUID()); + } +} + +void LLFriendCardsManager::onFriendListUpdate(U32 changed_mask) +{ + LLAvatarTracker& at = LLAvatarTracker::instance(); + + switch(changed_mask) { + case LLFriendObserver::ADD: + { + const std::set<LLUUID>& changed_items = at.getChangedIDs(); + std::set<LLUUID>::const_iterator id_it = changed_items.begin(); + std::set<LLUUID>::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + LLFriendCardsManager::instance().addFriendCardToInventory(*id_it); + } + } + break; + case LLFriendObserver::REMOVE: + { + const std::set<LLUUID>& changed_items = at.getChangedIDs(); + std::set<LLUUID>::const_iterator id_it = changed_items.begin(); + std::set<LLUUID>::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + LLFriendCardsManager::instance().removeFriendCardFromInventory(*id_it); + } + } + + default:; + } +} + +// EOF diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h new file mode 100644 index 0000000000..18a6d0ab69 --- /dev/null +++ b/indra/newview/llfriendcard.h @@ -0,0 +1,143 @@ +/** + * @file llfriendcard.h + * @brief Definition of classes to process Friends Cards + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFRIENDCARD_H +#define LL_LLFRIENDCARD_H + + +#include "llcallingcard.h" +#include "llinventorymodel.h" // for LLInventoryModel::item_array_t + +class LLViewerInventoryItem; + +class LLFriendCardsManager + : public LLSingleton<LLFriendCardsManager> + , public LLFriendObserver +{ + LOG_CLASS(LLFriendCardsManager); + + friend class LLSingleton<LLFriendCardsManager>; + friend class CreateFriendCardCallback; + +public: + typedef std::map<LLUUID, std::vector<LLUUID> > folderid_buddies_map_t; + + // LLFriendObserver implementation + void changed(U32 mask) + { + onFriendListUpdate(mask); + } + + /** + * Ensures that all necessary folders are created in Inventory. + * + * For now it processes Calling Card, Calling Card/Friends & Calling Card/Friends/All folders + */ + void ensureFriendFoldersExist(); + + + /** + * Determines if specified Inventory Calling Card exists in any of lists + * in the Calling Card/Friends/ folder (Default, or Custom) + */ + bool isItemInAnyFriendsList(const LLViewerInventoryItem* item); + + /** + * Checks is the specified category is in the Calling Card/Friends folder + */ + bool isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const; + + /** + * Synchronizes content of the Calling Card/Friends/All Global Inventory folder with Agent's Friend List + */ + void syncFriendsFolder(); + + /*! + * \brief + * Collects folders' IDs with the buddies' IDs in the Inventory Calling Card/Friends folder. + * + * \param folderBuddiesMap + * map into collected data will be put. It will be cleared before adding new data. + * + * Each item in the out map is a pair where first is an LLViewerInventoryCategory UUID, + * second is a vector with UUID of Avatars from this folder. + * + */ + void collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const; + +private: + LLFriendCardsManager(); + ~LLFriendCardsManager(); + + + /** + * Stores buddy id to avoid sent create_inventory_callingcard several time for the same Avatar + */ + void putAvatarData(const LLUUID& avatarID); + + /** + * Extracts buddy id of Created Friend Card + */ + const LLUUID extractAvatarID(const LLUUID& avatarID); + + bool isAvatarDataStored(const LLUUID& avatarID) const + { + return (mBuddyIDSet.end() != mBuddyIDSet.find(avatarID)); + } + + const LLUUID& findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& folderLabel) const; + const LLUUID& findFriendFolderUUIDImpl() const; + const LLUUID& findFriendAllSubfolderUUIDImpl() const; + const LLUUID& findFriendCardInventoryUUIDImpl(const LLUUID& avatarID); + void findMatchedFriendCards(const LLUUID& avatarID, LLInventoryModel::item_array_t& items) const; + + /** + * Adds avatar specified by its UUID into the Calling Card/Friends/All Global Inventory folder + */ + bool addFriendCardToInventory(const LLUUID& avatarID); + + /** + * Removes an avatar specified by its UUID from the Calling Card/Friends/All Global Inventory folder + * and from the all Custom Folders + */ + void removeFriendCardFromInventory(const LLUUID& avatarID); + + void onFriendListUpdate(U32 changed_mask); + + +private: + typedef std::set<LLUUID> avatar_uuid_set_t; + + avatar_uuid_set_t mBuddyIDSet; +}; + +#endif // LL_LLFRIENDCARD_H diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index efa97de692..789e628b67 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -58,6 +58,7 @@ #include "llfloaterworldmap.h" #include "llfocusmgr.h" #include "llfolderview.h" +#include "llfriendcard.h" #include "llavataractions.h" #include "llgesturemgr.h" #include "lliconctrl.h" @@ -162,10 +163,26 @@ std::string ICON_NAME[ICON_NAME_COUNT] = BOOL gAddToOutfit = FALSE; + +// +=================================================+ +// | LLInventoryPanelObserver | +// +=================================================+ +void LLInventoryPanelObserver::changed(U32 mask) +{ + mIP->modelChanged(mask); +} + + // +=================================================+ // | LLInvFVBridge | // +=================================================+ +LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : +mUUID(uuid), mInvType(LLInventoryType::IT_NONE) +{ + mInventoryPanel = inventory->getHandle(); +} + const std::string& LLInvFVBridge::getName() const { LLInventoryObject* obj = getInventoryObject(); @@ -2302,7 +2319,11 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else if(isAgentInventory()) // do not allow creating in library { - mItems.push_back(std::string("New Folder")); + LLViewerInventoryCategory *cat = getCategory(); + + // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. + if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) + mItems.push_back(std::string("New Folder")); mItems.push_back(std::string("New Script")); mItems.push_back(std::string("New Note")); mItems.push_back(std::string("New Gesture")); @@ -2310,7 +2331,6 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mItems.push_back(std::string("New Body Parts")); mItems.push_back(std::string("Change Type")); - LLViewerInventoryCategory *cat = getCategory(); if (cat && LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())) { mDisabledItems.push_back(std::string("Change Type")); @@ -2879,6 +2899,16 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // | LLLandmarkBridge | // +=================================================+ +LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags/* = 0x00*/) : +LLItemBridge(inventory, uuid) +{ + mVisited = FALSE; + if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) + { + mVisited = TRUE; + } +} + LLUIImagePtr LLLandmarkBridge::getIcon() const { return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE); @@ -3216,6 +3246,18 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, return rv; } +BOOL LLCallingCardBridge::removeItem() +{ + if (LLFriendCardsManager::instance().isItemInAnyFriendsList(getItem())) + { + LLAvatarActions::removeFriendDialog(getItem()->getCreatorUUID()); + return FALSE; + } + else + { + return LLItemBridge::removeItem(); + } +} // +=================================================+ // | LLNotecardBridge | // +=================================================+ @@ -3450,6 +3492,14 @@ void LLAnimationBridge::openItem() // static LLUUID LLObjectBridge::sContextMenuItemID; +LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : +LLItemBridge(inventory, uuid), mInvType(type) +{ + mAttachPt = (flags & 0xff); // low bye of inventory flags + + mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; +} + BOOL LLObjectBridge::isItemRemovable() { LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3af54c52ea..25859b7f73 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -38,9 +38,10 @@ #include "llviewercontrol.h" #include "llcallingcard.h" #include "llinventorymodel.h" -#include "llfloaterinventory.h" #include "llfoldervieweventlistener.h" +class LLInventoryPanel; + enum EInventoryIcon { TEXTURE_ICON_NAME, @@ -114,7 +115,7 @@ class LLInventoryPanelObserver : public LLInventoryObserver public: LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask) { mIP->modelChanged(mask); } + virtual void changed(U32 mask); protected: LLInventoryPanel* mIP; }; @@ -191,11 +192,7 @@ public: virtual void clearDisplayName() {} protected: - LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : - mUUID(uuid), mInvType(LLInventoryType::IT_NONE) - { - mInventoryPanel = inventory->getHandle(); - } + LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid); LLInventoryObject* getInventoryObject() const; LLInventoryModel* getInventoryModel() const; @@ -395,15 +392,7 @@ public: virtual void openItem(); protected: - LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags = 0x00) : - LLItemBridge(inventory, uuid) - { - mVisited = FALSE; - if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) - { - mVisited = TRUE; - } - } + LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags = 0x00); protected: BOOL mVisited; @@ -438,6 +427,7 @@ public: EDragAndDropType cargo_type, void* cargo_data); void refreshFolderViewItem(); + BOOL removeItem(); protected: LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ); @@ -515,13 +505,7 @@ public: LLInventoryObject* getObject() const; protected: - LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : - LLItemBridge(inventory, uuid), mInvType(type) - { - mAttachPt = (flags & 0xff); // low bye of inventory flags - - mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; - } + LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags); protected: static LLUUID sContextMenuItemID; // Only valid while the context menu is open. @@ -788,6 +772,7 @@ void wear_inventory_item_on_avatar(LLInventoryItem* item); void wear_outfit_by_name(const std::string& name); void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append); +class LLViewerJointAttachment; void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); // Move items from an in-world object's "Contents" folder to a specified diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp index efa15e05da..1666ec1336 100644 --- a/indra/newview/llmenucommands.cpp +++ b/indra/newview/llmenucommands.cpp @@ -50,7 +50,6 @@ #include "llfloaterdirectory.h" #include "llfloaterworldmap.h" #include "llgivemoney.h" -#include "llfloaterinventory.h" #include "lllineeditor.h" #include "llnotify.h" #include "llstatusbar.h" diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 7bf7ceb6d2..1d79ea4a21 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -38,6 +38,7 @@ #include "lllandmark.h" #include "llfloaterworldmap.h" +#include "llfloaterinventory.h" #include "llfoldervieweventlistener.h" #include "lllandmarklist.h" #include "llsidetray.h" diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 0b11270fb5..14cbbd6123 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -33,10 +33,13 @@ #ifndef LL_LLPANELLANDMARKS_H #define LL_LLPANELLANDMARKS_H -#include "llfloaterinventory.h" #include "llinventorymodel.h" #include "llpanelplacestab.h" +class LLFolderViewItem; +class LLInventoryPanel; +class LLSaveFolderState; + class LLLandmarksPanel : public LLPanelPlacesTab { public: diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 844e5122f4..697182c8fc 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -47,6 +47,7 @@ #include "llcallingcard.h" // for LLAvatarTracker #include "llfloateravatarpicker.h" //#include "llfloaterminiinspector.h" +#include "llfriendcard.h" #include "llavataractions.h" #include "llgroupactions.h" #include "llgrouplist.h" @@ -302,7 +303,7 @@ LLPanelPeople::LLPanelPeople() mFilterEditor(NULL), mTabContainer(NULL), mOnlineFriendList(NULL), - mOfflineFriendList(NULL), + mAllFriendList(NULL), mNearbyList(NULL), mRecentList(NULL) { @@ -337,7 +338,7 @@ BOOL LLPanelPeople::postBuild() mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); mOnlineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_online"); - mOfflineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_offline"); + mAllFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_all"); mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list"); @@ -354,11 +355,11 @@ BOOL LLPanelPeople::postBuild() friends_panel->childSetAction("del_btn", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); mOnlineFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mOnlineFriendList)); - mOfflineFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mOfflineFriendList)); + mAllFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mAllFriendList)); mNearbyList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mNearbyList)); mRecentList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mRecentList)); mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); - mOfflineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOfflineFriendList)); + mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); @@ -427,17 +428,25 @@ bool LLPanelPeople::updateFriendList(U32 changed_mask) // *TODO: it's suboptimal to rebuild the whole lists on online status change. - // save them to the online and offline friends vectors + // save them to the online and all friends vectors mOnlineFriendVec.clear(); - mOfflineFriendVec.clear(); + mAllFriendVec.clear(); + + LLFriendCardsManager::folderid_buddies_map_t listMap; + + // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. + LLFriendCardsManager::instance().collectFriendsLists(listMap); + if (listMap.size() > 0) + { + mAllFriendVec = listMap.begin()->second; + } + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); for (; buddy_it != all_buddies.end(); ++buddy_it) { LLUUID buddy_id = buddy_it->first; if (av_tracker.isBuddyOnline(buddy_id)) mOnlineFriendVec.push_back(buddy_id); - else - mOfflineFriendVec.push_back(buddy_id); } return filterFriendList(); @@ -477,19 +486,19 @@ bool LLPanelPeople::updateGroupList() bool LLPanelPeople::filterFriendList() { - if (!mOnlineFriendList || !mOfflineFriendList) + if (!mOnlineFriendList || !mAllFriendList) return true; // there's no point in further updates // We must always update Friends list to clear the latest removed friend. bool have_names = mOnlineFriendList->update(mOnlineFriendVec, mFilterSubString) & - mOfflineFriendList->update(mOfflineFriendVec, mFilterSubString); + mAllFriendList->update(mAllFriendVec, mFilterSubString); if (mOnlineFriendVec.size() == 0) mOnlineFriendList->setCommentText(getString("no_friends_online")); - if (mOfflineFriendVec.size() == 0) - mOfflineFriendList->setCommentText(getString("no_friends_offline")); + if (mAllFriendVec.size() == 0) + mAllFriendList->setCommentText(getString("no_friends")); return have_names; } @@ -615,7 +624,7 @@ LLUUID LLPanelPeople::getCurrentItemID() const if ((cur_online_friend = mOnlineFriendList->getCurrentID()).notNull()) return cur_online_friend; - return mOfflineFriendList->getCurrentID(); + return mAllFriendList->getCurrentID(); } if (cur_tab == NEARBY_TAB_NAME) @@ -720,12 +729,12 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLAvatarList* list) void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { - // Make sure only one of the friends lists (online/offline) has selection. + // Make sure only one of the friends lists (online/all) has selection. if (getActiveTabName() == FRIENDS_TAB_NAME) { if (list == mOnlineFriendList) - mOfflineFriendList->deselectAllItems(TRUE); - else if (list == mOfflineFriendList) + mAllFriendList->deselectAllItems(TRUE); + else if (list == mAllFriendList) mOnlineFriendList->deselectAllItems(TRUE); else llassert(0 && "commit on unknown friends list"); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index d0f78f4247..3358a70bac 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -116,7 +116,7 @@ private: LLFilterEditor* mFilterEditor; LLTabContainer* mTabContainer; LLAvatarList* mOnlineFriendList; - LLAvatarList* mOfflineFriendList; + LLAvatarList* mAllFriendList; LLAvatarList* mNearbyList; LLAvatarList* mRecentList; LLGroupList* mGroupList; @@ -142,7 +142,7 @@ private: typedef std::vector<LLUUID> uuid_vector_t; uuid_vector_t mNearbyVec; uuid_vector_t mOnlineFriendVec; - uuid_vector_t mOfflineFriendVec; + uuid_vector_t mAllFriendVec; uuid_vector_t mRecentVec; }; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index ad1dd74cc6..7cb9e61e72 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" #include "llassettype.h" +#include "llwindow.h" #include "lllandmark.h" @@ -51,6 +52,7 @@ #include "llpanelteleporthistory.h" #include "llsidetray.h" #include "lltoggleablemenu.h" +#include "llviewerinventory.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 7faabbb28b..ab253e012d 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -51,7 +51,6 @@ #include "llagent.h" #include "llvoavatarself.h" #include "llselectmgr.h" -#include "llfloaterinventory.h" #include "llviewerinventory.h" #include "llviewerwindow.h" #include "lltrans.h" diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 6fe23e8aeb..3bda30e0c6 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -36,7 +36,6 @@ #include "llbutton.h" #include "llresmgr.h" #include "llinventory.h" -#include "llfloaterinventory.h" #include "llvoavatarself.h" #include "llagent.h" // gAgent #include "llkeyframemotion.h" diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index 0f2b94ebd4..7659c50ed3 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -36,7 +36,6 @@ #include "llagent.h" // gAgent #include "llbutton.h" #include "llinventory.h" -#include "llfloaterinventory.h" #include "lllineeditor.h" #include "llpreviewsound.h" #include "llresmgr.h" diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 9122e49a06..9d7338c111 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -32,6 +32,8 @@ #include "llviewerprecompiledheaders.h" +#include "llwindow.h" + #include "llpreviewtexture.h" #include "llagent.h" @@ -39,7 +41,6 @@ #include "llfilepicker.h" #include "llfloaterreg.h" #include "llimagetga.h" -#include "llfloaterinventory.h" #include "llinventory.h" #include "llresmgr.h" #include "lltrans.h" diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 3ac9076e85..afa8e5f072 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -642,20 +642,18 @@ LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& para return NULL; } +// *TODO: Eliminate magic constants. static const S32 fake_offset = 132; static const S32 fake_top_offset = 18; void LLSideTray::resetPanelRect () { - LLNavigationBar* nav_bar = LLNavigationBar::getInstance(); - LLRect nav_rect = nav_bar->getRect(); const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray>()); - S32 panel_width = sidetray_params.default_button_width+sidetray_params.default_button_margin; - if(!mCollapsed) - panel_width+=mMaxBarWidth; + S32 panel_width = sidetray_params.default_button_width; + panel_width += mCollapsed ? sidetray_params.default_button_margin : mMaxBarWidth; S32 panel_height = parent_rect.getHeight()-fake_top_offset; @@ -671,9 +669,8 @@ void LLSideTray::setPanelRect () const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); - S32 panel_width = sidetray_params.default_button_width+sidetray_params.default_button_margin; - if(!mCollapsed) - panel_width+=mMaxBarWidth; + S32 panel_width = sidetray_params.default_button_width; + panel_width += mCollapsed ? sidetray_params.default_button_margin : mMaxBarWidth; S32 panel_height = parent_rect.getHeight()-fake_top_offset - nav_rect.getHeight(); S32 panel_top = parent_rect.mTop-fake_top_offset - nav_rect.getHeight(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 920ec0c65d..6c0481feaa 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -77,6 +77,7 @@ #include "llviewercontrol.h" #include "llvfs.h" #include "llxorcipher.h" // saved password, MAC address +#include "llwindow.h" #include "imageids.h" #include "message.h" #include "v3math.h" @@ -111,7 +112,7 @@ #include "llimagebmp.h" #include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llfloaterinventory.h" +#include "llfriendcard.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support #include "llpanellogin.h" @@ -2142,10 +2143,15 @@ bool idle_startup() } + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. + gInventory.buildParentChildMap(); + //all categories loaded. lets create "My Favorites" category gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE,true); - gInventory.buildParentChildMap(); + // lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" and fill it with buddies + LLFriendCardsManager::instance().syncFriendsFolder(); llinfos << "Setting Inventory changed mask and notifying observers" << llendl; gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 9cabcf4680..c724fb5315 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -46,7 +46,6 @@ #include "llfloaterregioninfo.h" #include "llfloaterscriptdebug.h" #include "llhudicon.h" -#include "llfloaterinventory.h" #include "llnavigationbar.h" #include "llkeyboard.h" #include "lllineeditor.h" @@ -224,7 +223,7 @@ void LLStatusBar::draw() LLPanel::draw(); } -BOOL LLStatusBar::handleRightMouseUp(S32 x, S32 y, MASK mask) +BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask) { if (mHideNavbarContextMenu) { @@ -603,7 +602,7 @@ void LLStatusBar::onHideNavbarContextMenuItemClicked(const LLSD& userdata) void LLStatusBar::onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { - handleRightMouseUp(x, y, mask); + handleRightMouseDown(x, y, mask); } // static diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 0cb3551768..b77db2c525 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -58,7 +58,7 @@ public: /*virtual*/ void draw(); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL postBuild(); // MANIPULATORS diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index b5dd34df15..c58457d599 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -51,7 +51,6 @@ #include "llhudmanager.h" #include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llfloaterinventory.h" #include "llmutelist.h" #include "llnotify.h" #include "llpreviewnotecard.h" diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 4645b9bf59..95ab40f9bf 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -799,14 +799,14 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, gAgent.sendReliableMessage(); } -void create_inventory_callingcard(const LLUUID& avatar_id) +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer<LLInventoryCallback> cb/*=NULL*/) { std::string item_desc = avatar_id.asString(); std::string item_name; gCacheName->getFullName(avatar_id, item_name); create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - LLUUID::null, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, - LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, NULL); + parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); } void copy_inventory_item( diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 8920fb053b..0bfb37f7e8 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -286,7 +286,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, U32 next_owner_perm, LLPointer<LLInventoryCallback> cb); -void create_inventory_callingcard(const LLUUID& avatar_id); +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent = LLUUID::null, LLPointer<LLInventoryCallback> cb=NULL); /** * @brief Securely create a new inventory item by copying from another. diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 7bbe2c89b4..de01e79803 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -39,7 +39,6 @@ #include "llinventory.h" #include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llfloaterinventory.h" #include "llviewertexteditor.h" diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 9bdf9d2aac..461f7fc1c7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -116,7 +116,6 @@ #include "llhudview.h" #include "llimagebmp.h" #include "llimagej2c.h" -#include "llfloaterinventory.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 98d8b27e09..018cce4b49 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -52,7 +52,6 @@ #include "llheadrotmotion.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llfloaterinventory.h" #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" @@ -5510,6 +5509,24 @@ void LLVOAvatar::sitDown(BOOL bSitting) //----------------------------------------------------------------------------- void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) { + if (isSelf()) + { + // Might be first sit + LLFirstUse::useSit(); + + gAgent.setFlying(FALSE); + gAgent.setThirdPersonHeadOffset(LLVector3::zero); + //interpolate to new camera position + gAgent.startCameraAnimation(); + // make sure we are not trying to autopilot + gAgent.stopAutoPilot(); + gAgent.setupSitCamera(); + if (gAgent.getForceMouselook()) + { + gAgent.changeCameraToMouselook(); + } + } + if (mDrawable.isNull()) { return; @@ -5531,23 +5548,6 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) stopMotion(ANIM_AGENT_BODY_NOISE); - if (isSelf()) - { - // Might be first sit - LLFirstUse::useSit(); - - gAgent.setFlying(FALSE); - gAgent.setThirdPersonHeadOffset(LLVector3::zero); - //interpolate to new camera position - gAgent.startCameraAnimation(); - // make sure we are not trying to autopilot - gAgent.stopAutoPilot(); - gAgent.setupSitCamera(); - if (gAgent.getForceMouselook()) - { - gAgent.changeCameraToMouselook(); - } - } } //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 9777e1ec21..a7b5b60842 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -54,7 +54,6 @@ #include "llheadrotmotion.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llfloaterinventory.h" #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index fce31a2c68..22823ea98b 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -19,8 +19,8 @@ name="no_friends_online" value="No friends online" /> <string - name="no_friends_offline" - value="No friends offline" /> + name="no_friends" + value="No friends" /> <string name="no_groups" value="No groups" /> @@ -153,14 +153,14 @@ can_resize="false" layout="topleft" min_height="100" - name="tab_offline" - title="Offline"> + name="tab_all" + title="All"> <panel follows="all" height="260" layout="topleft" left="0" - name="tab_offline_panel" + name="tab_all_panel" top="100" width="285"> <avatar_list @@ -169,7 +169,7 @@ height="255" layout="topleft" left="0" - name="avatars_offline" + name="avatars_all" top="0" width="285" /> </panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 4560a7138c..27b34d16a8 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -413,6 +413,10 @@ this texture in your inventory <string name="InvFolder Current Outfit">Current Outfit</string> <string name="InvFolder My Outfits">My Outfits</string> + <!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694--> + <string name="InvFolder Friends">Friends</string> + <string name="InvFolder All">All</string> + <!-- inventory FVBridge --> <string name="Buy">Buy</string> <string name="BuyforL$">Buy for L$</string> |