diff options
47 files changed, 1440 insertions, 930 deletions
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index f2cdad8854..2a0dcaf333 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1888,41 +1888,50 @@ void LLFloaterView::reshapeFloater(S32 width, S32 height, BOOL called_from_paren // dependents use same follow flags as their "dependee" continue; } - LLRect r = floaterp->getRect(); - - // Compute absolute distance from each edge of screen - S32 left_offset = llabs(r.mLeft - 0); - S32 right_offset = llabs(old_width - r.mRight); - - S32 top_offset = llabs(old_height - r.mTop); - S32 bottom_offset = llabs(r.mBottom - 0); // Make if follow the edge it is closest to U32 follow_flags = 0x0; - if (left_offset < right_offset) + if (floaterp->isMinimized()) { - follow_flags |= FOLLOWS_LEFT; + follow_flags |= (FOLLOWS_LEFT | FOLLOWS_TOP); } else { - follow_flags |= FOLLOWS_RIGHT; - } + LLRect r = floaterp->getRect(); - // "No vertical adjustment" usually means that the bottom of the view - // has been pushed up or down. Hence we want the floaters to follow - // the top. - if (!adjust_vertical) - { - follow_flags |= FOLLOWS_TOP; - } - else if (top_offset < bottom_offset) - { - follow_flags |= FOLLOWS_TOP; - } - else - { - follow_flags |= FOLLOWS_BOTTOM; + // Compute absolute distance from each edge of screen + S32 left_offset = llabs(r.mLeft - 0); + S32 right_offset = llabs(old_width - r.mRight); + + S32 top_offset = llabs(old_height - r.mTop); + S32 bottom_offset = llabs(r.mBottom - 0); + + + if (left_offset < right_offset) + { + follow_flags |= FOLLOWS_LEFT; + } + else + { + follow_flags |= FOLLOWS_RIGHT; + } + + // "No vertical adjustment" usually means that the bottom of the view + // has been pushed up or down. Hence we want the floaters to follow + // the top. + if (!adjust_vertical) + { + follow_flags |= FOLLOWS_TOP; + } + else if (top_offset < bottom_offset) + { + follow_flags |= FOLLOWS_TOP; + } + else + { + follow_flags |= FOLLOWS_BOTTOM; + } } floaterp->setFollows(follow_flags); @@ -2172,16 +2181,16 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) const LLFloater::Params& default_params = LLFloater::getDefaultParams(); S32 floater_header_size = default_params.header_height; static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0); - S32 col = 0; LLRect snap_rect_local = getLocalSnapRect(); - for(S32 row = snap_rect_local.mBottom; - row < snap_rect_local.getHeight() - floater_header_size; - row += floater_header_size ) //loop rows - { - for(col = snap_rect_local.mLeft; - col < snap_rect_local.getWidth() - minimized_width; - col += minimized_width) + for(S32 col = snap_rect_local.mLeft; + col < snap_rect_local.getWidth() - minimized_width; + col += minimized_width) + { + for(S32 row = snap_rect_local.mTop - floater_header_size; + row > floater_header_size; + row -= floater_header_size ) //loop rows { + bool foundGap = TRUE; for(child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b129bca1f3..9d44f34ea8 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -252,6 +252,7 @@ set(viewer_SOURCE_FILES llinventoryfilter.cpp llinventoryfunctions.cpp llinventorymodel.cpp + llinventoryobserver.cpp llinventorypanel.cpp llinventorysubtreepanel.cpp lljoystickbutton.cpp @@ -748,6 +749,7 @@ set(viewer_HEADER_FILES llinventoryfilter.h llinventoryfunctions.h llinventorymodel.h + llinventoryobserver.h llinventorypanel.h llinventorysubtreepanel.h lljoystickbutton.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 38f14793d9..8ad52784d3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4259,7 +4259,29 @@ <key>Value</key> <integer>0</integer> </map> - <key>LogMessages</key> + <key>LoginSRVTimeout</key> + <map> + <key>Comment</key> + <string>Duration in seconds of the login SRV request timeout</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>10.0</real> + </map> + <key>LoginSRVPump</key> + <map> + <key>Comment</key> + <string>Name of the message pump that handles SRV request</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>LLAres</string> + </map> + <key>LogMessages</key> <map> <key>Comment</key> <string>Log network traffic</string> @@ -5501,7 +5523,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>QAMode</key> <map> diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 9938c3db2b..9b4986247f 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -887,9 +887,8 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl; } - // What we do here is get the complete information on the items in - // the inventory, and set up an observer that will wait for that to - // happen. + // Get the complete information on the items in the inventory and set up an observer + // that will trigger when the complete information is fetched. LLInventoryFetchDescendentsObserver::folder_ref_t folders; folders.push_back(current_outfit_id); outfit->fetchDescendents(folders); @@ -2023,6 +2022,8 @@ void LLInitialWearablesFetch::done() else { processWearablesMessage(); + // Create links for attachments that may have arrived before the COF existed. + LLAppearanceManager::linkRegisteredAttachments(); } delete this; } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index d14de1c301..0901289dac 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1123,6 +1123,7 @@ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) { if (do_update) LLAppearanceManager::updateAppearanceFromCOF(); + return; } else { @@ -1134,6 +1135,7 @@ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) LLAssetType::AT_LINK, cb); } + return; } /* static */ @@ -1281,3 +1283,22 @@ void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id) //llinfos << "no link changes, inv link not enabled" << llendl; } } + +/* static */ +void LLAppearanceManager::linkRegisteredAttachments() +{ + for (std::set<LLUUID>::iterator it = sRegisteredAttachments.begin(); + it != sRegisteredAttachments.end(); + ++it) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + { + wearItem(item, false); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + } + sRegisteredAttachments.clear(); +} diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 56f54dfc23..7dea16b6cf 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -71,6 +71,7 @@ public: static void unregisterAttachment(const LLUUID& item_id); static void registerAttachment(const LLUUID& item_id); static void setAttachmentInvLinkEnable(bool val); + static void linkRegisteredAttachments(); private: static void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f631978565..ee4a9df15f 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -192,7 +192,7 @@ void LLAvatarActions::startIM(const LLUUID& id) // static void LLAvatarActions::startCall(const LLUUID& id) { - if (id.isNull() || isCalling(id)) + if (id.isNull()) { return; } diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 291f645ea2..8d57c68cf2 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -40,6 +40,7 @@ #include "llimfloater.h" // for LLIMFloater #include "lllayoutstack.h" #include "llnearbychatbar.h" +#include "llspeakbutton.h" #include "llsplitbutton.h" #include "llsyswellwindow.h" #include "llfloatercamera.h" @@ -185,6 +186,28 @@ void LLBottomTray::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& } } +// virtual +void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + // Time it takes to connect to voice channel might be pretty long, + // so don't expect user login or STATUS_VOICE_ENABLED to be followed by STATUS_JOINED. + BOOL enable = FALSE; + + switch (status) + { + // Do not add STATUS_VOICE_ENABLED because voice chat is + // inactive until STATUS_JOINED + case STATUS_JOINED: + enable = TRUE; + break; + default: + enable = FALSE; + break; + } + + mSpeakBtn->setEnabled(enable); +} + //virtual void LLBottomTray::onFocusLost() { @@ -280,6 +303,19 @@ BOOL LLBottomTray::postBuild() mSnapshotPanel = getChild<LLPanel>("snapshot_panel"); setRightMouseDownCallback(boost::bind(&LLBottomTray::showBottomTrayContextMenu,this, _2, _3,_4)); + mSpeakBtn = getChild<LLSpeakButton>("talk"); + + // Speak button should be initially disabled because + // it takes some time between logging in to world and connecting to voice channel. + mSpeakBtn->setEnabled(FALSE); + + // Localization tool doesn't understand custom buttons like <talk_button> + mSpeakBtn->setSpeakToolTip( getString("SpeakBtnToolTip") ); + mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") ); + + // Registering Chat Bar to receive Voice client status change notifications. + gVoiceClient->addObserver(this); + if (mChicletPanel && mToolbarStack && mNearbyChatBar) { verifyChildControlsSizes(); diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 2972a2b1ac..3847168ae1 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -33,7 +33,7 @@ #ifndef LL_LLBOTTOMPANEL_H #define LL_LLBOTTOMPANEL_H -#include <llmenugl.h> +#include "llmenugl.h" #include "llpanel.h" #include "llimview.h" @@ -51,6 +51,7 @@ class LLBottomTray : public LLSingleton<LLBottomTray> , public LLPanel , public LLIMSessionObserver + , public LLVoiceClientStatusObserver { LOG_CLASS(LLBottomTray); friend class LLSingleton<LLBottomTray>; @@ -75,6 +76,10 @@ public: virtual void onFocusLost(); virtual void setVisible(BOOL visible); + // Implements LLVoiceClientStatusObserver::onChange() to enable the speak + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + void showBottomTrayContextMenu(S32 x, S32 y, MASK mask); void showGestureButton(BOOL visible); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 0b8b5935f8..87b801d73b 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -848,8 +848,11 @@ void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) } - //update the speakers dropdown too - mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); + //update the speakers dropdown too, if it's available + if (mSpeakerPanel) + { + mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); + } } } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 9c38d9c5fc..ee785e7ecb 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -46,6 +46,7 @@ #include "llagent.h" #include "llavatariconctrl.h" +#include "llbottomtray.h" #include "llcallingcard.h" #include "llchat.h" #include "llresmgr.h" @@ -73,6 +74,7 @@ #include "llvoicechannel.h" #include "lltrans.h" #include "llrecentpeople.h" +#include "llsyswellwindow.h" #include "llfirstuse.h" #include "llagentui.h" @@ -1087,16 +1089,90 @@ LLIMMgr::onConfirmForceCloseError( //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLOutgoingCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : + LLDockableFloater(NULL, false, payload), + mPayload(payload) +{ +} + +void LLOutgoingCallDialog::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRectRaw(); +} + +void LLOutgoingCallDialog::onOpen(const LLSD& key) +{ + // tell the user which voice channel they are leaving + if (!mPayload["old_channel_name"].asString().empty()) + { + childSetTextArg("leaving", "[CURRENT_CHAT]", mPayload["old_channel_name"].asString()); + } + else + { + childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat")); + } + + std::string callee_name = mPayload["session_name"].asString(); + if (callee_name == "anonymous") + { + callee_name = getString("anonymous"); + } + + setTitle(callee_name); + + LLSD callee_id = mPayload["other_user_id"]; + childSetTextArg("calling", "[CALLEE_NAME]", callee_name); + LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); + icon->setValue(callee_id); + + // dock the dialog to the sys well, where other sys messages appear + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + this, getDockTongue(), LLDockControl::TOP, + boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); +} + + +//static +void LLOutgoingCallDialog::onCancel(void* user_data) +{ + LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; + + if (!gIMMgr) + return; + + LLUUID session_id = self->mPayload["session_id"].asUUID(); + gIMMgr->endCall(session_id); + + self->closeFloater(); +} + + +BOOL LLOutgoingCallDialog::postBuild() +{ + BOOL success = LLDockableFloater::postBuild(); + + childSetAction("Cancel", onCancel, this); + + return success; +} + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIncomingCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : - LLModalDialog(payload), + LLDockableFloater(NULL, false, payload), mPayload(payload) { } BOOL LLIncomingCallDialog::postBuild() { + LLDockableFloater::postBuild(); + LLSD caller_id = mPayload["caller_id"]; EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); @@ -1115,6 +1191,11 @@ BOOL LLIncomingCallDialog::postBuild() call_type = getString("VoiceInviteAdHoc"); } + // check to see if this is an Avaline call + LLUUID session_id = mPayload["session_id"].asUUID(); + bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id);
+ childSetVisible("Start IM", is_avatar); // no IM for avaline + LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); caller_name_widget->setValue(caller_name + " " + call_type); LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); @@ -1128,6 +1209,30 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } +void LLIncomingCallDialog::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRectRaw(); +} + +void LLIncomingCallDialog::onOpen(const LLSD& key) +{ + // tell the user which voice channel they would be leaving + LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); + if (voice && !voice->getSessionName().empty()) + { + childSetTextArg("question", "[CURRENT_CHAT]", voice->getSessionName()); + } + else + { + childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat")); + } + + // dock the dialog to the sys well, where other sys messages appear + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + this, getDockTongue(), LLDockControl::TOP, + boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); +} + //static void LLIncomingCallDialog::onAccept(void* user_data) { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index c566b111ca..62a54bc081 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,9 +34,11 @@ #define LL_LLIMVIEW_H #include "lldarray.h" +#include "lldockablefloater.h" #include "llspeakers.h" //for LLIMSpeakerMgr #include "llimpanel.h" //for voice channels #include "llmodaldialog.h" +#include "lldockablefloater.h" #include "llinstantmessage.h" #include "lluuid.h" #include "llmultifloater.h" @@ -401,12 +403,13 @@ private: LLSD mPendingAgentListUpdates; }; -class LLIncomingCallDialog : public LLModalDialog +class LLIncomingCallDialog : public LLDockableFloater { public: LLIncomingCallDialog(const LLSD& payload); /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); static void onAccept(void* user_data); static void onReject(void* user_data); @@ -414,6 +417,23 @@ public: private: void processCallResponse(S32 response); + void getAllowedRect(LLRect& rect); + + LLSD mPayload; +}; + +class LLOutgoingCallDialog : public LLDockableFloater +{ +public: + LLOutgoingCallDialog(const LLSD& payload); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + + static void onCancel(void* user_data); + +private: + void getAllowedRect(LLRect& rect); LLSD mPayload; }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e7d7eb19d0..4b0d524906 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -176,6 +176,7 @@ LLInventoryModel::LLInventoryModel() mRootFolderID(), mLibraryRootFolderID(), mLibraryOwnerID(), + mIsNotifyObservers(FALSE), mIsAgentInvUsable(false) { } @@ -537,7 +538,10 @@ void LLInventoryModel::updateLinkedItems(const LLUUID& object_id) item_array, LLInventoryModel::INCLUDE_TRASH, is_linked_item_match); - + if (cat_array.empty() && item_array.empty()) + { + return; + } for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); cat_iter != cat_array.end(); cat_iter++) @@ -639,6 +643,7 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) new_item = old_item; LLUUID old_parent_id = old_item->getParentUUID(); LLUUID new_parent_id = item->getParentUUID(); + if(old_parent_id != new_parent_id) { // need to update the parent-child tree @@ -1133,6 +1138,15 @@ BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const // The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328] void LLInventoryModel::notifyObservers(const std::string service_name) { + if (mIsNotifyObservers) + { + // Within notifyObservers, something called notifyObservers + // again. This type of recursion is unsafe because it causes items to be + // processed twice, and this can easily lead to infinite loops. + llwarns << "Call was made to notifyObservers within notifyObservers!" << llendl; + return; + } + mIsNotifyObservers = TRUE; for (observer_list_t::iterator iter = mObservers.begin(); iter != mObservers.end(); ) { @@ -1154,12 +1168,21 @@ void LLInventoryModel::notifyObservers(const std::string service_name) mModifyMask = LLInventoryObserver::NONE; mChangedItemIDs.clear(); + mIsNotifyObservers = FALSE; } // store flag for change // and id of object change applies to void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) { + if (mIsNotifyObservers) + { + // Something marked an item for change within a call to notifyObservers + // (which is in the process of processing the list of items marked for change). + // This means the change may fail to be processed. + llwarns << "Adding changed mask within notify observers! Change will likely be lost." << llendl; + } + mModifyMask |= mask; if (referent.notNull()) { @@ -1833,13 +1856,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) { //llinfos << "LLInventoryModel::addItem()" << llendl; - - // This can happen if assettype enums change. This can be a backwards compatibility issue - // in some viewer prototypes prior to when the AT_LINK enum changed from 23 to 24. + // This can happen if assettype enums from llassettype.h ever change. + // For example, there is a known backwards compatibility issue in some viewer prototypes prior to when + // the AT_LINK enum changed from 23 to 24. if ((item->getType() == LLAssetType::AT_NONE) || LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) { - llwarns << "Got bad asset type for item ( name: " << item->getName() << " type: " << item->getType() << " inv-type: " << item->getInventoryType() << " ), ignoring." << llendl; + llwarns << "Got bad asset type for item [ name: " << item->getName() << " type: " << item->getType() << " inv-type: " << item->getInventoryType() << " ], ignoring." << llendl; return; } if(item) @@ -1848,7 +1871,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) // The item will show up as a broken link. if (item->getIsBrokenLink()) { - llinfos << "Adding broken link ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl; + llinfos << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl; } mItemMap[item->getUUID()] = item; } @@ -2176,7 +2199,7 @@ bool LLInventoryModel::loadSkeleton( // Add all the items loaded which are parented to a // category with a correctly cached parent - count = items.count(); + S32 bad_link_count = 0; cat_map_t::iterator unparented = mCategoryMap.end(); for(item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); @@ -2193,7 +2216,11 @@ bool LLInventoryModel::loadSkeleton( // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. if (item->getIsBrokenLink()) { - llinfos << "Attempted to add cached link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; + bad_link_count++; + lldebugs << "Attempted to add cached link item without baseobj present ( name: " + << item->getName() << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; invalid_categories.insert(cit->second); continue; } @@ -2203,6 +2230,12 @@ bool LLInventoryModel::loadSkeleton( } } } + if (bad_link_count > 0) + { + llinfos << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << "The corresponding categories were invalidated." << llendl; + } } else { @@ -3307,6 +3340,12 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) for(i = 0; i < count; ++i) { titem->unpackMessage(msg, _PREHASH_ItemData, i); + // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added. + if (gInventory.getItem(titem->getUUID())) + { + llinfos << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl; + continue; + } gInventory.updateItem(titem); } @@ -3682,513 +3721,6 @@ bool LLNameCategoryCollector::operator()( return false; } - - -///---------------------------------------------------------------------------- -/// Observers -///---------------------------------------------------------------------------- - -void LLInventoryCompletionObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } -} - -void LLInventoryCompletionObserver::watchItem(const LLUUID& id) -{ - if(id.notNull()) - { - mIncomplete.push_back(id); - } -} - - -void LLInventoryFetchObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - // BUG: This can cause done() to get called prematurely below. - // This happens with the LLGestureInventoryFetchObserver that - // loads gestures at startup. JC - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } - //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; - //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -bool LLInventoryFetchObserver::isEverythingComplete() const -{ - return mIncomplete.empty(); -} - -void fetch_items_from_llsd(const LLSD& items_llsd) -{ - if (!items_llsd.size()) return; - LLSD body; - body[0]["cap_name"] = "FetchInventory"; - body[1]["cap_name"] = "FetchLib"; - for (S32 i=0; i<items_llsd.size();i++) - { - if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString()) - { - body[0]["items"].append(items_llsd[i]); - continue; - } - if (items_llsd[i]["owner_id"].asString() == ALEXANDRIA_LINDEN_ID.asString()) - { - body[1]["items"].append(items_llsd[i]); - continue; - } - } - - for (S32 i=0; i<body.size(); i++) - { - if (0 >= body[i].size()) continue; - std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString()); - - if (!url.empty()) - { - body[i]["agent_id"] = gAgent.getID(); - LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); - break; - } - - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - for (S32 j=0; j<body[i]["items"].size(); j++) - { - LLSD item_entry = body[i]["items"][j]; - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_FetchInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); - msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); - if(msg->isSendFull(NULL)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - } - } -} - -void LLInventoryFetchObserver::fetchItems( - const LLInventoryFetchObserver::item_ref_t& ids) -{ - LLUUID owner_id; - LLSD items_llsd; - for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(item) - { - if(item->isComplete()) - { - // It's complete, so put it on the complete container. - mComplete.push_back(*it); - continue; - } - else - { - owner_id = item->getPermissions().getOwner(); - } - } - else - { - // assume it's agent inventory. - owner_id = gAgent.getID(); - } - - // It's incomplete, so put it on the incomplete container, and - // pack this on the message. - mIncomplete.push_back(*it); - - // Prepare the data to fetch - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*it); - items_llsd.append(item_entry); - } - fetch_items_from_llsd(items_llsd); -} - -// virtual -void LLInventoryFetchDescendentsObserver::changed(U32 mask) -{ - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(isComplete(cat)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - if(mIncompleteFolders.empty()) - { - done(); - } -} - -void LLInventoryFetchDescendentsObserver::fetchDescendents( - const folder_ref_t& ids) -{ - for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) continue; - if(!isComplete(cat)) - { - cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. - mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. - } - else - { - mCompleteFolders.push_back(*it); - } - } -} - -bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const -{ - return mIncompleteFolders.empty(); -} - -bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) -{ - S32 version = cat->getVersion(); - S32 descendents = cat->getDescendentCount(); - if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) - || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) - { - return false; - } - // it might be complete - check known descendents against - // currently available. - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); - if(!cats || !items) - { - // bit of a hack - pretend we're done if they are gone or - // incomplete. should never know, but it would suck if this - // kept tight looping because of a corrupt memory state. - return true; - } - S32 known = cats->count() + items->count(); - if(descendents == known) - { - // hey - we're done. - return true; - } - return false; -} - -void LLInventoryFetchComboObserver::changed(U32 mask) -{ - if(!mIncompleteItems.empty()) - { - for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncompleteItems.erase(it); - continue; - } - if(item->isComplete()) - { - mCompleteItems.push_back(*it); - it = mIncompleteItems.erase(it); - continue; - } - ++it; - } - } - if(!mIncompleteFolders.empty()) - { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(gInventory.isCategoryComplete(*it)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - } - if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) - { - mDone = true; - done(); - } -} - -void LLInventoryFetchComboObserver::fetch( - const folder_ref_t& folder_ids, - const item_ref_t& item_ids) -{ - lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; - for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); - if(!cat) continue; - if(!gInventory.isCategoryComplete(*fit)) - { - cat->fetchDescendents(); - lldebugs << "fetching folder " << *fit <<llendl; - mIncompleteFolders.push_back(*fit); - } - else - { - mCompleteFolders.push_back(*fit); - lldebugs << "completing folder " << *fit <<llendl; - } - } - - // Now for the items - we fetch everything which is not a direct - // descendent of an incomplete folder because the item will show - // up in an inventory descendents message soon enough so we do not - // have to fetch it individually. - LLSD items_llsd; - LLUUID owner_id; - for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit) - { - LLViewerInventoryItem* item = gInventory.getItem(*iit); - if(!item) - { - lldebugs << "uanble to find item " << *iit << llendl; - continue; - } - if(item->isComplete()) - { - // It's complete, so put it on the complete container. - mCompleteItems.push_back(*iit); - lldebugs << "completing item " << *iit << llendl; - continue; - } - else - { - mIncompleteItems.push_back(*iit); - owner_id = item->getPermissions().getOwner(); - } - if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) - { - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*iit); - items_llsd.append(item_entry); - } - else - { - lldebugs << "not worrying about " << *iit << llendl; - } - } - fetch_items_from_llsd(items_llsd); -} - -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ - if(id.notNull()) - { - mMIA.push_back(id); - } -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mMIA.empty()) - { - for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - ++it; - continue; - } - mExist.push_back(*it); - it = mMIA.erase(it); - } - if(mMIA.empty()) - { - done(); - } - } -} - -void LLInventoryAddedObserver::changed(U32 mask) -{ - if(!(mask & LLInventoryObserver::ADD)) - { - return; - } - - // *HACK: If this was in response to a packet off - // the network, figure out which item was updated. - LLMessageSystem* msg = gMessageSystem; - - std::string msg_name; - if (mMessageName.empty()) - { - msg_name = msg->getMessageName(); - } - else - { - msg_name = mMessageName; - } - - if (msg_name.empty()) - { - return; - } - - // We only want newly created inventory items. JC - if ( msg_name != "UpdateCreateInventoryItem") - { - return; - } - - LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < num_blocks; ++i) - { - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - if (!(titem->getUUID().isNull())) - { - //we don't do anything with null keys - mAdded.push_back(titem->getUUID()); - } - } - if (!mAdded.empty()) - { - done(); - } -} - -LLInventoryTransactionObserver::LLInventoryTransactionObserver( - const LLTransactionID& transaction_id) : - mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ - if(mask & LLInventoryObserver::ADD) - { - // This could be it - see if we are processing a bulk update - LLMessageSystem* msg = gMessageSystem; - if(msg->getMessageName() - && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) - { - // we have a match for the message - now check the - // transaction id. - LLUUID id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); - if(id == mTransactionID) - { - // woo hoo, we found it - folder_ref_t folders; - item_ref_t items; - S32 count; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - S32 i; - for(i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); - if(id.notNull()) - { - folders.push_back(id); - } - } - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - for(i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); - if(id.notNull()) - { - items.push_back(id); - } - } - - // call the derived class the implements this method. - done(folders, items); - } - } - } -} - - ///---------------------------------------------------------------------------- /// LLAssetIDMatches ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index faf026887a..bd64591194 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -41,40 +41,27 @@ #include "lluuid.h" #include "llpermissionsflags.h" #include "llstring.h" - #include <map> #include <set> #include <string> #include <vector> -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryObserver -// -// This class is designed to be a simple abstract base class which can -// relay messages when the inventory changes. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ! REFACTOR ! Remove llinventoryobservers.h and have other files that need it explicitly +// include llinventoryobservers.h instead of llinventorymodel.h . This will reduce dependency on +// llinventorymodel.h. +#include "llinventoryobserver.h" + +class LLInventoryObserver; +class LLInventoryObject; +class LLInventoryItem; +class LLInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLMessageSystem; +class LLInventoryCollectFunctor; -class LLInventoryObserver -{ -public: - // This enumeration is a way to refer to what changed in a more - // human readable format. You can mask the value provided by - // chaged() to see if the observer is interested in the change. - enum - { - NONE = 0, - LABEL = 1, // name changed - INTERNAL = 2, // internal change, eg, asset uuid different - ADD = 4, // something added - REMOVE = 8, // something deleted - STRUCTURE = 16, // structural change, eg, item or folder moved - CALLING_CARD = 32, // online, grant status, cancel, etc change - ALL = 0xffffffff - }; - virtual ~LLInventoryObserver() {}; - virtual void changed(U32 mask) = 0; - std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328] -}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryModel @@ -87,16 +74,6 @@ public: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryObject; -class LLInventoryItem; -class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLMessageSystem; -class LLInventoryCollectFunctor; - class LLInventoryModel { public: @@ -473,23 +450,12 @@ protected: cat_array_t* getUnlockedCatArray(const LLUUID& id); item_array_t* getUnlockedItemArray(const LLUUID& id); -protected: +private: // Variables used to track what has changed since the last notify. U32 mModifyMask; typedef std::set<LLUUID> changed_items_t; changed_items_t mChangedItemIDs; - // Information for tracking the actual inventory. We index this - // information in a lot of different ways so we can access - // the inventory using several different identifiers. - // mInventory member data is the 'master' list of inventory, and - // mCategoryMap and mItemMap store uuid->object mappings. - typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t; - typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t; - //inv_map_t mInventory; - cat_map_t mCategoryMap; - item_map_t mItemMap; - std::map<LLUUID, bool> mCategoryLock; std::map<LLUUID, bool> mItemLock; @@ -525,6 +491,21 @@ protected: // This flag is used to handle an invalid inventory state. bool mIsAgentInvUsable; +private: + // Information for tracking the actual inventory. We index this + // information in a lot of different ways so we can access + // the inventory using several different identifiers. + // mInventory member data is the 'master' list of inventory, and + // mCategoryMap and mItemMap store uuid->object mappings. + typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t; + typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t; + //inv_map_t mInventory; + cat_map_t mCategoryMap; + item_map_t mItemMap; + + // Flag set when notifyObservers is being called, to look for bugs + // where it's called recursively. + BOOL mIsNotifyObservers; public: // *NOTE: DEBUG functionality void dumpInventory() const; @@ -767,183 +748,5 @@ public: LLInventoryItem* item); }; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryCompletionObserver -// -// Class which can be used as a base class for doing something when -// when all observed items are locally complete. This class implements -// the changed() method of LLInventoryObserver and declares a new -// method named done() which is called when all watched items have -// complete information in the inventory model. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryCompletionObserver : public LLInventoryObserver -{ -public: - LLInventoryCompletionObserver() {} - virtual void changed(U32 mask); - - void watchItem(const LLUUID& id); - -protected: - virtual void done() = 0; - - typedef std::vector<LLUUID> item_ref_t; - item_ref_t mComplete; - item_ref_t mIncomplete; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles all the the fetching necessary. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryFetchObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchObserver() {} - virtual void changed(U32 mask); - - typedef std::vector<LLUUID> item_ref_t; - - bool isEverythingComplete() const; - void fetchItems(const item_ref_t& ids); - virtual void done() = 0; - -protected: - item_ref_t mComplete; - item_ref_t mIncomplete; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchDescendentsObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles fetching based on category. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchDescendentsObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchDescendentsObserver() {} - virtual void changed(U32 mask); - - typedef std::vector<LLUUID> folder_ref_t; - void fetchDescendents(const folder_ref_t& ids); - bool isEverythingComplete() const; - virtual void done() = 0; - -protected: - bool isComplete(LLViewerInventoryCategory* cat); - folder_ref_t mIncompleteFolders; - folder_ref_t mCompleteFolders; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchComboObserver -// -// This class does an appropriate combination of fetch descendents and -// item fetches based on completion of categories and items. Much like -// the fetch and fetch descendents, this will call done() when everything -// has arrived. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchComboObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchComboObserver() : mDone(false) {} - virtual void changed(U32 mask); - - typedef std::vector<LLUUID> folder_ref_t; - typedef std::vector<LLUUID> item_ref_t; - void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); - - virtual void done() = 0; - -protected: - bool mDone; - folder_ref_t mCompleteFolders; - folder_ref_t mIncompleteFolders; - item_ref_t mCompleteItems; - item_ref_t mIncompleteItems; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -// This class is used as a base class for doing somethign when all the -// observed item ids exist in the inventory somewhere. You can derive -// a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: - LLInventoryExistenceObserver() {} - virtual void changed(U32 mask); - - void watchItem(const LLUUID& id); - -protected: - virtual void done() = 0; - - typedef std::vector<LLUUID> item_ref_t; - item_ref_t mExist; - item_ref_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryAddedObserver -// -// This class is used as a base class for doing something when -// a new item arrives in inventory. -// It does not watch for a certain UUID, rather it acts when anything is added -// Derive a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryAddedObserver : public LLInventoryObserver -{ -public: - LLInventoryAddedObserver() : mAdded() {} - virtual void changed(U32 mask); - -protected: - virtual void done() = 0; - - typedef std::vector<LLUUID> item_ref_t; - item_ref_t mAdded; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -// Class which can be used as a base class for doing something when an -// inventory transaction completes. -// -// *NOTE: This class is not quite complete. Avoid using unless you fix up it's -// functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: - LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - virtual void changed(U32 mask); - -protected: - typedef std::vector<LLUUID> folder_ref_t; - typedef std::vector<LLUUID> item_ref_t; - virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; - - LLTransactionID mTransactionID; -}; - - #endif // LL_LLINVENTORYMODEL_H diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp new file mode 100644 index 0000000000..3ccf593d27 --- /dev/null +++ b/indra/newview/llinventoryobserver.cpp @@ -0,0 +1,564 @@ +/** + * @file llinventoryobserver.cpp + * @brief Implementation of the inventory observers used to track agent inventory. + * + * $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 "llinventoryobserver.h" + +#include "llassetstorage.h" +#include "llcrc.h" +#include "lldir.h" +#include "llsys.h" +#include "llxfermanager.h" +#include "message.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llfloater.h" +#include "llfocusmgr.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llviewerregion.h" +#include "llappviewer.h" +#include "lldbstrings.h" +#include "llviewerstats.h" +#include "llmutelist.h" +#include "llnotifications.h" +#include "llcallbacklist.h" +#include "llpreview.h" +#include "llviewercontrol.h" +#include "llvoavatarself.h" +#include "llsdutil.h" +#include <deque> + +void LLInventoryCompletionObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mIncomplete.empty()) + { + for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + it = mIncomplete.erase(it); + continue; + } + if(item->isComplete()) + { + mComplete.push_back(*it); + it = mIncomplete.erase(it); + continue; + } + ++it; + } + if(mIncomplete.empty()) + { + done(); + } + } +} + +void LLInventoryCompletionObserver::watchItem(const LLUUID& id) +{ + if(id.notNull()) + { + mIncomplete.push_back(id); + } +} + + +void LLInventoryFetchObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mIncomplete.empty()) + { + for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + // BUG: This can cause done() to get called prematurely below. + // This happens with the LLGestureInventoryFetchObserver that + // loads gestures at startup. JC + it = mIncomplete.erase(it); + continue; + } + if(item->isComplete()) + { + mComplete.push_back(*it); + it = mIncomplete.erase(it); + continue; + } + ++it; + } + if(mIncomplete.empty()) + { + done(); + } + } + //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; + //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; +} + +bool LLInventoryFetchObserver::isEverythingComplete() const +{ + return mIncomplete.empty(); +} + +void fetch_items_from_llsd(const LLSD& items_llsd) +{ + if (!items_llsd.size()) return; + LLSD body; + body[0]["cap_name"] = "FetchInventory"; + body[1]["cap_name"] = "FetchLib"; + for (S32 i=0; i<items_llsd.size();i++) + { + if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString()) + { + body[0]["items"].append(items_llsd[i]); + continue; + } + if (items_llsd[i]["owner_id"].asString() == ALEXANDRIA_LINDEN_ID.asString()) + { + body[1]["items"].append(items_llsd[i]); + continue; + } + } + + for (S32 i=0; i<body.size(); i++) + { + if (0 >= body[i].size()) continue; + std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString()); + + if (!url.empty()) + { + body[i]["agent_id"] = gAgent.getID(); + LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); + break; + } + + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + for (S32 j=0; j<body[i]["items"].size(); j++) + { + LLSD item_entry = body[i]["items"][j]; + if(start_new_message) + { + start_new_message = FALSE; + msg->newMessageFast(_PREHASH_FetchInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); + msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); + if(msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + } + } +} + +void LLInventoryFetchObserver::fetchItems( + const LLInventoryFetchObserver::item_ref_t& ids) +{ + LLUUID owner_id; + LLSD items_llsd; + for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(item) + { + if(item->isComplete()) + { + // It's complete, so put it on the complete container. + mComplete.push_back(*it); + continue; + } + else + { + owner_id = item->getPermissions().getOwner(); + } + } + else + { + // assume it's agent inventory. + owner_id = gAgent.getID(); + } + + // It's incomplete, so put it on the incomplete container, and + // pack this on the message. + mIncomplete.push_back(*it); + + // Prepare the data to fetch + LLSD item_entry; + item_entry["owner_id"] = owner_id; + item_entry["item_id"] = (*it); + items_llsd.append(item_entry); + } + fetch_items_from_llsd(items_llsd); +} + +// virtual +void LLInventoryFetchDescendentsObserver::changed(U32 mask) +{ + for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) + { + it = mIncompleteFolders.erase(it); + continue; + } + if(isComplete(cat)) + { + mCompleteFolders.push_back(*it); + it = mIncompleteFolders.erase(it); + continue; + } + ++it; + } + if(mIncompleteFolders.empty()) + { + done(); + } +} + +void LLInventoryFetchDescendentsObserver::fetchDescendents( + const folder_ref_t& ids) +{ + for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) continue; + if(!isComplete(cat)) + { + cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. + mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. + } + else + { + mCompleteFolders.push_back(*it); + } + } +} + +bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const +{ + return mIncompleteFolders.empty(); +} + +bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) +{ + S32 version = cat->getVersion(); + S32 descendents = cat->getDescendentCount(); + if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) + || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) + { + return false; + } + // it might be complete - check known descendents against + // currently available. + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); + if(!cats || !items) + { + // bit of a hack - pretend we're done if they are gone or + // incomplete. should never know, but it would suck if this + // kept tight looping because of a corrupt memory state. + return true; + } + S32 known = cats->count() + items->count(); + if(descendents == known) + { + // hey - we're done. + return true; + } + return false; +} + +void LLInventoryFetchComboObserver::changed(U32 mask) +{ + if(!mIncompleteItems.empty()) + { + for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + it = mIncompleteItems.erase(it); + continue; + } + if(item->isComplete()) + { + mCompleteItems.push_back(*it); + it = mIncompleteItems.erase(it); + continue; + } + ++it; + } + } + if(!mIncompleteFolders.empty()) + { + for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) + { + it = mIncompleteFolders.erase(it); + continue; + } + if(gInventory.isCategoryComplete(*it)) + { + mCompleteFolders.push_back(*it); + it = mIncompleteFolders.erase(it); + continue; + } + ++it; + } + } + if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) + { + mDone = true; + done(); + } +} + +void LLInventoryFetchComboObserver::fetch( + const folder_ref_t& folder_ids, + const item_ref_t& item_ids) +{ + lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; + for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); + if(!cat) continue; + if(!gInventory.isCategoryComplete(*fit)) + { + cat->fetchDescendents(); + lldebugs << "fetching folder " << *fit <<llendl; + mIncompleteFolders.push_back(*fit); + } + else + { + mCompleteFolders.push_back(*fit); + lldebugs << "completing folder " << *fit <<llendl; + } + } + + // Now for the items - we fetch everything which is not a direct + // descendent of an incomplete folder because the item will show + // up in an inventory descendents message soon enough so we do not + // have to fetch it individually. + LLSD items_llsd; + LLUUID owner_id; + for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit) + { + LLViewerInventoryItem* item = gInventory.getItem(*iit); + if(!item) + { + lldebugs << "uanble to find item " << *iit << llendl; + continue; + } + if(item->isComplete()) + { + // It's complete, so put it on the complete container. + mCompleteItems.push_back(*iit); + lldebugs << "completing item " << *iit << llendl; + continue; + } + else + { + mIncompleteItems.push_back(*iit); + owner_id = item->getPermissions().getOwner(); + } + if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) + { + LLSD item_entry; + item_entry["owner_id"] = owner_id; + item_entry["item_id"] = (*iit); + items_llsd.append(item_entry); + } + else + { + lldebugs << "not worrying about " << *iit << llendl; + } + } + fetch_items_from_llsd(items_llsd); +} + +void LLInventoryExistenceObserver::watchItem(const LLUUID& id) +{ + if(id.notNull()) + { + mMIA.push_back(id); + } +} + +void LLInventoryExistenceObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mMIA.empty()) + { + for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + ++it; + continue; + } + mExist.push_back(*it); + it = mMIA.erase(it); + } + if(mMIA.empty()) + { + done(); + } + } +} + +void LLInventoryAddedObserver::changed(U32 mask) +{ + if(!(mask & LLInventoryObserver::ADD)) + { + return; + } + + // *HACK: If this was in response to a packet off + // the network, figure out which item was updated. + LLMessageSystem* msg = gMessageSystem; + + std::string msg_name; + if (mMessageName.empty()) + { + msg_name = msg->getMessageName(); + } + else + { + msg_name = mMessageName; + } + + if (msg_name.empty()) + { + return; + } + + // We only want newly created inventory items. JC + if ( msg_name != "UpdateCreateInventoryItem") + { + return; + } + + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < num_blocks; ++i) + { + titem->unpackMessage(msg, _PREHASH_InventoryData, i); + if (!(titem->getUUID().isNull())) + { + //we don't do anything with null keys + mAdded.push_back(titem->getUUID()); + } + } + if (!mAdded.empty()) + { + done(); + } +} + +LLInventoryTransactionObserver::LLInventoryTransactionObserver( + const LLTransactionID& transaction_id) : + mTransactionID(transaction_id) +{ +} + +void LLInventoryTransactionObserver::changed(U32 mask) +{ + if(mask & LLInventoryObserver::ADD) + { + // This could be it - see if we are processing a bulk update + LLMessageSystem* msg = gMessageSystem; + if(msg->getMessageName() + && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) + { + // we have a match for the message - now check the + // transaction id. + LLUUID id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); + if(id == mTransactionID) + { + // woo hoo, we found it + folder_ref_t folders; + item_ref_t items; + S32 count; + count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + S32 i; + for(i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); + if(id.notNull()) + { + folders.push_back(id); + } + } + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + for(i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); + if(id.notNull()) + { + items.push_back(id); + } + } + + // call the derived class the implements this method. + done(folders, items); + } + } + } +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h new file mode 100644 index 0000000000..384e6292e8 --- /dev/null +++ b/indra/newview/llinventoryobserver.h @@ -0,0 +1,249 @@ +/** + * @file llinventoryobserver.h + * @brief LLInventoryObserver class header file + * + * $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_LLINVENTORYOBSERVERS_H +#define LL_LLINVENTORYOBSERVERS_H + +#include "lluuid.h" +#include <string> +#include <vector> + +class LLViewerInventoryCategory; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryObserver +// +// This class is designed to be a simple abstract base class which can +// relay messages when the inventory changes. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryObserver +{ +public: + // This enumeration is a way to refer to what changed in a more + // human readable format. You can mask the value provided by + // chaged() to see if the observer is interested in the change. + enum + { + NONE = 0, + LABEL = 1, // name changed + INTERNAL = 2, // internal change, eg, asset uuid different + ADD = 4, // something added + REMOVE = 8, // something deleted + STRUCTURE = 16, // structural change, eg, item or folder moved + CALLING_CARD = 32, // online, grant status, cancel, etc change + ALL = 0xffffffff + }; + virtual ~LLInventoryObserver() {}; + virtual void changed(U32 mask) = 0; + std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328] +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCompletionObserver +// +// Class which can be used as a base class for doing something when +// when all observed items are locally complete. This class implements +// the changed() method of LLInventoryObserver and declares a new +// method named done() which is called when all watched items have +// complete information in the inventory model. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryCompletionObserver : public LLInventoryObserver +{ +public: + LLInventoryCompletionObserver() {} + virtual void changed(U32 mask); + + void watchItem(const LLUUID& id); + +protected: + virtual void done() = 0; + + typedef std::vector<LLUUID> item_ref_t; + item_ref_t mComplete; + item_ref_t mIncomplete; +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles all the the fetching necessary. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryFetchObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchObserver() {} + virtual void changed(U32 mask); + + typedef std::vector<LLUUID> item_ref_t; + + bool isEverythingComplete() const; + void fetchItems(const item_ref_t& ids); + virtual void done() = 0; + +protected: + item_ref_t mComplete; + item_ref_t mIncomplete; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchDescendentsObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles fetching based on category. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchDescendentsObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchDescendentsObserver() {} + virtual void changed(U32 mask); + + typedef std::vector<LLUUID> folder_ref_t; + void fetchDescendents(const folder_ref_t& ids); + bool isEverythingComplete() const; + virtual void done() = 0; + +protected: + bool isComplete(LLViewerInventoryCategory* cat); + folder_ref_t mIncompleteFolders; + folder_ref_t mCompleteFolders; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchComboObserver +// +// This class does an appropriate combination of fetch descendents and +// item fetches based on completion of categories and items. Much like +// the fetch and fetch descendents, this will call done() when everything +// has arrived. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchComboObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchComboObserver() : mDone(false) {} + virtual void changed(U32 mask); + + typedef std::vector<LLUUID> folder_ref_t; + typedef std::vector<LLUUID> item_ref_t; + void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); + + virtual void done() = 0; + +protected: + bool mDone; + folder_ref_t mCompleteFolders; + folder_ref_t mIncompleteFolders; + item_ref_t mCompleteItems; + item_ref_t mIncompleteItems; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryExistenceObserver +// +// This class is used as a base class for doing somethign when all the +// observed item ids exist in the inventory somewhere. You can derive +// a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryExistenceObserver : public LLInventoryObserver +{ +public: + LLInventoryExistenceObserver() {} + virtual void changed(U32 mask); + + void watchItem(const LLUUID& id); + +protected: + virtual void done() = 0; + + typedef std::vector<LLUUID> item_ref_t; + item_ref_t mExist; + item_ref_t mMIA; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryAddedObserver +// +// This class is used as a base class for doing something when +// a new item arrives in inventory. +// It does not watch for a certain UUID, rather it acts when anything is added +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryAddedObserver : public LLInventoryObserver +{ +public: + LLInventoryAddedObserver() : mAdded() {} + virtual void changed(U32 mask); + +protected: + virtual void done() = 0; + + typedef std::vector<LLUUID> item_ref_t; + item_ref_t mAdded; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryTransactionObserver +// +// Class which can be used as a base class for doing something when an +// inventory transaction completes. +// +// *NOTE: This class is not quite complete. Avoid using unless you fix up it's +// functionality gaps. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryTransactionObserver : public LLInventoryObserver +{ +public: + LLInventoryTransactionObserver(const LLTransactionID& transaction_id); + virtual void changed(U32 mask); + +protected: + typedef std::vector<LLUUID> folder_ref_t; + typedef std::vector<LLUUID> item_ref_t; + virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; + + LLTransactionID mTransactionID; +}; + + +#endif // LL_LLINVENTORYOBSERVERS_H + diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 9a71e53441..dfd4af5c28 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -191,11 +191,9 @@ BOOL LLInventoryPanel::postBuild() {
rebuildViewsFor(mStartFolderID);
mHasInventoryConnection = true;
+ defaultOpenInventory();
}
- // bit of a hack to make sure the inventory is open.
- mFolders->openFolder(preferred_type != LLFolderType::FT_NONE ? LLViewerFolderType::lookupNewCategoryName(preferred_type) : "My Inventory");
-
if (mSortOrderSetting != INHERIT_SORT_ORDER)
{
setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
@@ -300,6 +298,7 @@ void LLInventoryPanel::modelChanged(U32 mask) {
rebuildViewsFor(mStartFolderID);
mHasInventoryConnection = true;
+ defaultOpenInventory();
return;
}
@@ -561,6 +560,25 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) }
}
+// bit of a hack to make sure the inventory is open.
+void LLInventoryPanel::defaultOpenInventory()
+{
+ const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString);
+ if (preferred_type != LLFolderType::FT_NONE)
+ {
+ const std::string& top_level_folder_name = LLViewerFolderType::lookupNewCategoryName(preferred_type);
+ mFolders->openFolder(top_level_folder_name);
+ }
+ else
+ {
+ // Get the first child (it should be "My Inventory") and
+ // open it up by name (just to make sure the first child is actually a folder).
+ LLView* first_child = mFolders->getFirstChild();
+ const std::string& first_child_name = first_child->getName();
+ mFolders->openFolder(first_child_name);
+ }
+}
+
struct LLConfirmPurgeData
{
LLUUID mID;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 9f74fad5c1..e398c44105 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -165,7 +165,7 @@ protected: // Given the id and the parent, build all of the folder views. void rebuildViewsFor(const LLUUID& id); virtual void buildNewViews(const LLUUID& id); // made virtual to support derived classes. EXT-719 - + void defaultOpenInventory(); // open the first level of inventory protected: LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 945294f3f2..a01426ea87 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -182,6 +182,9 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials) mRequestData["method"] = "login_to_simulator"; mRequestData["params"] = request_params; mRequestData["options"] = requested_options; + + mRequestData["cfg_srv_timeout"] = gSavedSettings.getF32("LoginSRVTimeout"); + mRequestData["cfg_srv_pump"] = gSavedSettings.getString("LoginSRVPump"); } bool LLLoginInstance::handleLoginEvent(const LLSD& event) diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 3993431311..94b8791147 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -36,7 +36,6 @@ #include "lltrans.h" #include "llnearbychatbar.h" -#include "llspeakbutton.h" #include "llbottomtray.h" #include "llagent.h" #include "llgesturemgr.h" @@ -234,14 +233,6 @@ BOOL LLNearbyChatBar::postBuild() mOutputMonitor = getChild<LLOutputMonitorCtrl>("chat_zone_indicator"); mOutputMonitor->setVisible(FALSE); - mSpeakBtn = getParent()->getChild<LLSpeakButton>("talk"); - - // Speak button should be initially disabled because - // it takes some time between logging in to world and connecting to voice channel. - mSpeakBtn->setEnabled(FALSE); - - // Registering Chat Bar to receive Voice client status change notifications. - gVoiceClient->addObserver(this); return TRUE; } @@ -733,27 +724,6 @@ public: } }; -void LLNearbyChatBar::onChange(EStatusType status, const std::string &channelURI, bool proximal) -{ - // Time it takes to connect to voice channel might be pretty long, - // so don't expect user login or STATUS_VOICE_ENABLED to be followed by STATUS_JOINED. - BOOL enable = FALSE; - - switch (status) - { - // Do not add STATUS_VOICE_ENABLED because voice chat is - // inactive until STATUS_JOINED - case STATUS_JOINED: - enable = TRUE; - break; - default: - enable = FALSE; - break; - } - - mSpeakBtn->setEnabled(enable); -} - // Creating the object registers with the dispatcher. LLChatHandler gChatHandler; diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h index 56ee706a97..224118e088 100644 --- a/indra/newview/llnearbychatbar.h +++ b/indra/newview/llnearbychatbar.h @@ -42,9 +42,6 @@ #include "llspeakers.h" -class LLSpeakButton; - - class LLGestureComboBox : public LLComboBox , public LLGestureManagerObserver @@ -76,7 +73,6 @@ protected: class LLNearbyChatBar : public LLPanel -, public LLVoiceClientStatusObserver { public: // constructor for inline chat-bars (e.g. hosted in chat history window) @@ -105,11 +101,6 @@ public: S32 getMinWidth() const; S32 getMaxWidth() const; - /** - * Implements LLVoiceClientStatusObserver::onChange() - */ - /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - protected: static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str); static void onChatBoxKeystroke(LLLineEditor* caller, void* userdata); @@ -127,7 +118,6 @@ protected: static S32 sLastSpecialChatChannel; LLLineEditor* mChatBox; - LLSpeakButton* mSpeakBtn; LLOutputMonitorCtrl* mOutputMonitor; LLLocalSpeakerMgr* mSpeakerMgr; }; diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 1770138b3e..9cd949c9cc 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -174,10 +174,8 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) getChild<LLAvatarIconCtrl>("avatar_icon")->setValue(mAvatarID); - // Fetch the currect name - gCacheName->get(mAvatarID, FALSE, boost::bind(&LLPanelIMControlPanel::nameUpdatedCallback, this, _1, _2, _3, _4)); - - // Disable profile button if participant is not realy SL avatar + // Disable most profile buttons if the participant is + // not really an SL avatar (e.g., an Avaline caller). LLIMModel::LLIMSession* im_session = im_model.findIMSession(session_id); if( im_session && !im_session->mOtherParticipantIsAvatar ) @@ -188,6 +186,13 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) childSetEnabled("share_btn", FALSE); childSetEnabled("teleport_btn", FALSE); childSetEnabled("pay_btn", FALSE); + + getChild<LLTextBox>("avatar_name")->setValue(im_session->mName);
+ } + else + { + // If the participant is an avatar, fetch the currect name + gCacheName->get(mAvatarID, FALSE, boost::bind(&LLPanelIMControlPanel::nameUpdatedCallback, this, _1, _2, _3, _4)); } } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 15a75cb930..e3b2ab77aa 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -204,11 +204,6 @@ void LLPanelMainInventory::initListCommandsHandlers() mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this));
mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
mListCommands->childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
- /*
- mListCommands->getChild<LLButton>("add_btn")->setHeldDownCallback(boost::bind(&LLPanelMainInventory::onAddButtonHeldDown, this));
- static const LLSD add_landmark_command("add_landmark");
- mListCommands->childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddAction, this, add_landmark_command));
- */
LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn");
trash_btn->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 9ba94c8ca9..2bbb2b7153 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -1193,7 +1193,7 @@ void LLPanelPeople::onCallButtonClicked() if (selected_uuids.size() == 1) { // initiate a P2P voice chat with the selected user - LLAvatarActions::startCall(selected_uuids[0]); + LLAvatarActions::startCall(getCurrentItemID()); } else if (selected_uuids.size() > 1) { diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 8c5439d47e..6ca6734598 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -435,7 +435,7 @@ void LLSpatialGroup::clearDrawMap() BOOL LLSpatialGroup::isRecentlyVisible() const { - return (LLDrawable::getCurrentFrame() - (S32)mVisible) < LLDrawable::getMinVisFrameRange() ; + return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; } BOOL LLSpatialGroup::isVisible() const diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp index 57ea018f25..51d53b2674 100644 --- a/indra/newview/llspeakbutton.cpp +++ b/indra/newview/llspeakbutton.cpp @@ -133,6 +133,16 @@ LLSpeakButton::~LLSpeakButton() LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn); } +void LLSpeakButton::setSpeakToolTip(const std::string& msg) +{ + mSpeakBtn->setToolTip(msg); +} + +void LLSpeakButton::setShowToolTip(const std::string& msg) +{ + mShowBtn->setToolTip(msg); +} + void LLSpeakButton::onMouseDown_SpeakBtn() { bool down = true; diff --git a/indra/newview/llspeakbutton.h b/indra/newview/llspeakbutton.h index e213c562dd..02c8ab3890 100644 --- a/indra/newview/llspeakbutton.h +++ b/indra/newview/llspeakbutton.h @@ -62,6 +62,11 @@ public: /*virtual*/ ~LLSpeakButton(); /*virtual*/ void draw(); + // *HACK: Need to put tooltips in a translatable location, + // the panel that contains this button. + void setSpeakToolTip(const std::string& msg); + void setShowToolTip(const std::string& msg); + protected: friend class LLUICtrlFactory; LLSpeakButton(const Params& p); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 64dcd7b97f..2c59d62b4b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -873,6 +873,9 @@ bool idle_startup() gViewerWindow->getWindow()->show(); display_startup(); + //DEV-10530. do cleanup. remove at some later date. jan-2009 + LLFloaterPreference::cleanupBadSetting(); + // DEV-16927. The following code removes errant keystrokes that happen while the window is being // first made visible. #ifdef _WIN32 @@ -1900,9 +1903,6 @@ bool idle_startup() //DEV-17797. get null folder. Any items found here moved to Lost and Found LLInventoryModel::findLostItems(); - //DEV-10530. do cleanup. remove at some later date. jan-2009 - LLFloaterPreference::cleanupBadSetting(); - LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); return FALSE; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 964d3bc2fa..7772f613f0 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -197,7 +197,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); - + LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); LLFloaterReg::add("parcel_info", "floater_preview_url.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterParcelInfo>); LLFloaterPayUtil::registerFloater(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 976d89a5b7..728fb7c616 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1879,7 +1879,9 @@ class LLAdvancedDebugAvatarTextures : public view_listener_t { bool handleEvent(const LLSD& userdata) { +#ifndef LL_RELEASE_FOR_DOWNLOAD handle_debug_avatar_textures(NULL); +#endif return true; } }; @@ -1893,7 +1895,9 @@ class LLAdvancedDumpAvatarLocalTextures : public view_listener_t { bool handleEvent(const LLSD& userdata) { +#ifndef LL_RELEASE_FOR_DOWNLOAD handle_dump_avatar_local_textures(NULL); +#endif return true; } }; @@ -7860,10 +7864,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); - #ifndef LL_RELEASE_FOR_DOWNLOAD view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); - #endif // Advanced > Network view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 9923c9ac74..85bc26c9c0 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -206,33 +206,31 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( const LLUUID &image_id, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, LLHost request_from_host) { - llassert_always(boost_priority >= LLViewerTexture::BOOST_NONE) ; return gTextureList.getImage(image_id, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ; } LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( const std::string& filename, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, const LLUUID& force_id) { - llassert_always(boost_priority >= LLViewerTexture::BOOST_NONE) ; return gTextureList.getImageFromFile(filename, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; } //static LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, @@ -1485,9 +1483,8 @@ F32 LLViewerFetchedTexture::calcDecodePriority() if ( mBoostLevel > BOOST_HIGH) { priority += 10000000.f; - } - - if(mAdditionalDecodePriority > 0.0f) + } + else if(mAdditionalDecodePriority > 0.0f) { // 1-9 S32 additional_priority = (S32)(1.0f + mAdditionalDecodePriority*8.0f + .5f); // round @@ -3147,8 +3144,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() if(mNeedsResetMaxVirtualSize) { - mMaxVirtualSize = 0.f ;//reset - mNeedsResetMaxVirtualSize = FALSE ; + addTextureStats(0.f, FALSE) ;//reset } if(mIsPlaying) //media is playing diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index bde87d1dd5..141979052d 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -107,12 +107,11 @@ public: enum EBoostLevel { - //skip 0 and 1 to avoid mistakenly mixing boost level with boolean numbers. - BOOST_NONE = 2, - BOOST_AVATAR_BAKED = 3, - BOOST_AVATAR = 4, - BOOST_CLOUDS = 5, - BOOST_SCULPTED = 6, + BOOST_NONE = 0, + BOOST_AVATAR_BAKED = 1, + BOOST_AVATAR = 2, + BOOST_CLOUDS = 3, + BOOST_SCULPTED = 4, BOOST_HIGH = 10, BOOST_TERRAIN = 11, // has to be high priority for minimap / low detail @@ -668,7 +667,7 @@ public: static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -677,7 +676,7 @@ public: static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -686,7 +685,7 @@ public: static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 081b7cc483..703a13976c 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -325,7 +325,7 @@ void LLViewerTextureList::restoreGL() LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, @@ -345,7 +345,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, @@ -411,7 +411,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, @@ -441,7 +441,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, //when this function is called, there is no such texture in the gTextureList with image_id. LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, BOOL usemipmaps, - S32 boost_priority, + LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, LLGLenum primary_format, @@ -1346,7 +1346,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority) const BOOL use_mips = FALSE; const LLRect scale_rect = LLRect::null; - return loadUIImageByID(image_id, use_mips, scale_rect, priority); + return loadUIImageByID(image_id, use_mips, scale_rect, (LLViewerTexture::EBoostLevel)priority); } LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority) @@ -1360,21 +1360,27 @@ LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priori const BOOL use_mips = FALSE; const LLRect scale_rect = LLRect::null; - return loadUIImageByName(image_name, image_name, use_mips, scale_rect, priority); + return loadUIImageByName(image_name, image_name, use_mips, scale_rect, (LLViewerTexture::EBoostLevel)priority); } LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std::string& filename, - BOOL use_mips, const LLRect& scale_rect, S32 boost_priority ) + BOOL use_mips, const LLRect& scale_rect, LLViewerTexture::EBoostLevel boost_priority ) { - if (boost_priority == 0) boost_priority = LLViewerFetchedTexture::BOOST_UI; + if (boost_priority == LLViewerTexture::BOOST_NONE) + { + boost_priority = LLViewerTexture::BOOST_UI; + } LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTextureFromFile(filename, MIPMAP_NO, boost_priority); return loadUIImage(imagep, name, use_mips, scale_rect); } LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, - BOOL use_mips, const LLRect& scale_rect, S32 boost_priority) + BOOL use_mips, const LLRect& scale_rect, LLViewerTexture::EBoostLevel boost_priority) { - if (boost_priority == 0) boost_priority = LLViewerFetchedTexture::BOOST_UI; + if (boost_priority == LLViewerTexture::BOOST_NONE) + { + boost_priority = LLViewerTexture::BOOST_UI; + } LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id, MIPMAP_NO, boost_priority); return loadUIImage(imagep, id.asString(), use_mips, scale_rect); } diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 3c9c81a689..028f8441ab 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -130,7 +130,7 @@ private: LLViewerFetchedTexture * getImage(const LLUUID &image_id, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -139,7 +139,7 @@ private: LLViewerFetchedTexture * getImageFromFile(const std::string& filename, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -148,7 +148,7 @@ private: LLViewerFetchedTexture* getImageFromUrl(const std::string& url, BOOL usemipmap = TRUE, - BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -157,7 +157,7 @@ private: LLViewerFetchedTexture* createImage(const LLUUID &image_id, BOOL usemipmap = TRUE, - S32 boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, LLGLint internal_format = 0, LLGLenum primary_format = 0, @@ -228,9 +228,11 @@ public: static void onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); private: LLUIImagePtr loadUIImageByName(const std::string& name, const std::string& filename, - BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, S32 boost_priority = 0); + BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI); LLUIImagePtr loadUIImageByID(const LLUUID& id, - BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, S32 boost_priority = 0); + BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, + LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI); LLUIImagePtr loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 89649407ff..d93913b944 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -306,8 +306,10 @@ void LLVoiceChannel::activate() // activating the proximal channel between IM calls LLVoiceChannel* old_channel = sCurrentVoiceChannel; sCurrentVoiceChannel = this; + mCallDialogPayload["old_channel_name"] = ""; if (old_channel) { + mCallDialogPayload["old_channel_name"] = old_channel->getSessionName(); old_channel->deactivate(); } } @@ -870,6 +872,19 @@ void LLVoiceChannelP2P::setState(EState state) { // HACK: Open/close the call window if needed. toggleCallWindowIfNeeded(state); + + // *HACK: open outgoing call floater if needed, might be better done elsewhere. + mCallDialogPayload["session_id"] = mSessionID; + mCallDialogPayload["session_name"] = mSessionName; + mCallDialogPayload["other_user_id"] = mOtherUserID; + if (!mReceivedCall && state == STATE_RINGING) + { + llinfos << "RINGINGGGGGGGG " << mSessionName << llendl; + if (!mSessionName.empty()) + { + LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE); + } + } // you only "answer" voice invites in p2p mode // so provide a special purpose message here diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 20b6157b48..639585de55 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -109,6 +109,7 @@ protected: EState mState; std::string mSessionName; LLSD mNotifyArgs; + LLSD mCallDialogPayload; BOOL mIgnoreNextSessionLeave; LLHandle<LLPanel> mLoginNotificationHandle; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 39d4bb0c02..5fedfc943b 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1598,7 +1598,7 @@ void LLVoiceClient::stateMachine() } else { - LL_WARNS("Voice") << "region doesn't have ParcelVoiceInfoRequest capability. This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL; + LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability. This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL; } } } @@ -4273,7 +4273,7 @@ void LLVoiceClient::mediaStreamUpdatedEvent( if(incoming) { // Send the voice chat invite to the GUI layer - // TODO: Question: Should we correlate with the mute list here? + // *TODO: Question: Should we correlate with the mute list here? session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID); session->mVoiceInvitePending = true; if(session->mName.empty()) diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index 8d3165b98c..9897f40c4e 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -196,7 +196,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 // END DEBUG //LL_INFOS("World Map") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL; - LLPointer<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + LLPointer<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); img->setBoostLevel(LLViewerTexture::BOOST_MAP); // Return the smart pointer diff --git a/indra/newview/skins/default/xui/en/floater_incoming_call.xml b/indra/newview/skins/default/xui/en/floater_incoming_call.xml index 16873df310..9c2898945b 100644 --- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml +++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml @@ -4,13 +4,17 @@ can_close="false" can_minimize="false" can_tear_off="false" - height="200" + height="125" layout="topleft" name="incoming call" help_topic="incoming_call" title="UNKNOWN PERSON IS CALLING" - width="240"> - <floater.string + width="410"> + <floater.string + name="localchat"> + Local Voice Chat + </floater.string> + <floater.string name="anonymous"> anonymous </floater.string> @@ -31,18 +35,26 @@ left_delta="19" top="35" width="36" /> - <text_editor - font="SansSerif" - height="64" - border_visible="false" + <text + font="SansSerifLarge" + height="20" layout="topleft" left="77" - max_length="2147483647" name="caller name" - read_only="true" - top="21" - width="163" + top="27" + width="315" word_wrap="true" /> + <text + font="SansSerif" + height="50" + layout="topleft" + left="77" + name="question" + top="52" + width="315" + word_wrap="true"> + Do you want to leave [CURRENT_CHAT] and join this voice chat? + </text> <button height="24" label="Accept" @@ -57,16 +69,14 @@ label="Reject" label_selected="Reject" layout="topleft" - left_delta="0" name="Reject" - top_pad="12" + left_pad="10" width="100" /> <button height="24" label="Start IM" layout="topleft" - left_delta="0" name="Start IM" - top_pad="12" + left_pad="10" width="100" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index 30639f955f..b48c962413 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -36,10 +36,10 @@ filename="panel_main_inventory.xml" follows="all" layout="topleft" + hide_top_panel="true" left="0" label="Inventory Panel" name="Inventory Panel" top="15" - width="467"> -</panel> + width="467" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml new file mode 100644 index 0000000000..44956f7e52 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + can_close="false" + can_minimize="false" + can_tear_off="false" + height="125" + layout="topleft" + name="outgoing call" + help_topic="outgoing_call" + title="CALLING" + width="410"> + <floater.string + name="localchat"> + Local Voice Chat + </floater.string> + <floater.string + name="anonymous"> + anonymous + </floater.string> + <floater.string + name="VoiceInviteP2P"> + is calling. + </floater.string> + <floater.string + name="VoiceInviteAdHoc"> + has joined a Voice Chat call with a conference chat. + </floater.string> + <avatar_icon + enabled="false" + follows="left|top" + height="36" + image_name="icon_avatar_online.tga" + layout="topleft" + left_delta="19" + top="35" + width="36" /> + <text + font="SansSerifLarge" + height="20" + layout="topleft" + left="77" + name="calling" + top="27" + width="315" + word_wrap="true"> +Calling [CALLEE_NAME] + </text> + <text + font="SansSerif" + height="50" + layout="topleft" + left="77" + name="leaving" + top="52" + width="315" + word_wrap="true"> +Leaving [CURRENT_CHAT]. + </text> + <button + height="24" + label="Cancel" + label_selected="Cancel" + left="70" + layout="topleft" + name="Cancel" + left_pad="10" + width="100" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_tos.xml b/indra/newview/skins/default/xui/en/floater_tos.xml index 4e2cce1428..1adb824e2a 100644 --- a/indra/newview/skins/default/xui/en/floater_tos.xml +++ b/indra/newview/skins/default/xui/en/floater_tos.xml @@ -53,22 +53,6 @@ Please read the following Terms of Service carefully. To continue logging in to [SECOND_LIFE], you must accept the agreement. </text> - <text_editor - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="283" - layout="topleft" - left_delta="0" - max_length="65536" - name="tos_text" - top_pad="43" - width="568" - handle_edit_keys_directly="true" - word_wrap="true"> - TOS_TEXT - </text_editor> <web_browser follows="left|top" height="340" @@ -76,6 +60,6 @@ you must accept the agreement. left_delta="0" name="tos_html" start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E" - top_delta="-27" + top_delta="0" width="568" /> </floater> diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 8188016455..3c16a439d9 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -13,6 +13,8 @@ chrome="true" border_visible="false" width="1000"> + <string name="SpeakBtnToolTip">Turns microphone on/off</string> + <string name="VoiceControlBtnToolTip">Shows/hides voice control panel</string> <layout_stack mouse_opaque="false" border_size="0" @@ -70,9 +72,7 @@ left="0" name="talk" top="3" - width="100" - speak_button.tool_tip="Turns microphone on/off" - show_button.tool_tip="Shows/hides voice control panel" /> + width="100" /> </layout_panel> <icon auto_resize="false" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index ea66bfa197..761c17cfd2 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2863,7 +2863,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. Connecting... </string> <string name="conference-title"> - Friends Conference + Ad-hoc Conference </string> <string name="inventory_item_offered-im"> Inventory item offered diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index d31a81e128..7b28a3b72c 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -76,6 +76,7 @@ LLControlGroup::LLControlGroup(const std::string& name) : LLControlGroup::~LLControlGroup() {} void LLControlGroup::setBOOL(const std::string& name, BOOL val) {} BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; } +F32 LLControlGroup::getF32(const std::string& name) { return 0.0f; } U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; } void LLControlGroup::setString(const std::string& name, const std::string& val) {} std::string LLControlGroup::getString(const std::string& name) { return "test_string"; } diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 7a30315b9a..b14c59ab9a 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -70,7 +70,7 @@ public: LLEventPump& getEventPump() { return mPump; } private: - void sendProgressEvent(const std::string& state, const std::string& change, + LLSD getProgressEventLLSD(const std::string& state, const std::string& change, const LLSD& data = LLSD()) { LLSD status_data; @@ -87,7 +87,13 @@ private: { status_data["data"] = data; } + return status_data; + } + void sendProgressEvent(const std::string& state, const std::string& change, + const LLSD& data = LLSD()) + { + LLSD status_data = getProgressEventLLSD(state, change, data); mPump.post(status_data); } @@ -140,15 +146,28 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential // Request SRV record. LL_INFOS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL; - // *NOTE:Mani - Completely arbitrary timeout value for SRV request. - filter.errorAfter(5, "SRV Request timed out!"); + // *NOTE:Mani - Completely arbitrary default timeout value for SRV request. + F32 seconds_to_timeout = 5.0f; + if(credentials.has("cfg_srv_timeout")) + { + seconds_to_timeout = credentials["cfg_srv_timeout"].asReal(); + } + + filter.eventAfter(seconds_to_timeout, + getProgressEventLLSD("offline", "fail.login")); + + std::string srv_pump_name = "LLAres"; + if(credentials.has("cfg_srv_pump")) + { + srv_pump_name = credentials["cfg_srv_pump"].asString(); + } - // Make request + // Make request LLSD request; request["op"] = "rewriteURI"; request["uri"] = uri; request["reply"] = replyPump.getName(); - rewrittenURIs = postAndWait(self, request, "LLAres", filter); + rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); } // we no longer need the filter LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp index a8ae2883d5..56c21016bd 100644 --- a/indra/viewer_components/login/tests/lllogin_test.cpp +++ b/indra/viewer_components/login/tests/lllogin_test.cpp @@ -47,6 +47,7 @@ public: bool call(const LLSD& event) { mDebug(STRINGIZE("LoginListener called!: " << event)); + mLastEvent = event; return false; } @@ -414,4 +415,40 @@ namespace tut ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline"); } + + template<> template<> + void llviewerlogin_object::test<5>() + { + DEBUG; + // Test SRV request timeout. + set_test_name("LLLogin SRV timeout testing"); + + // Testing normal login procedure. + LLEventStream llaresPump("LLAres"); // Dummy LLAres pump. + + // LLAresListener dummyLLAres("dummy_llares"); + // dummyLLAres.listenTo(llaresPump); + + LLLogin login; + LoginListener listener("test_ear"); + listener.listenTo(login.getEventPump()); + + LLSD credentials; + credentials["first"] = "these"; + credentials["last"] = "don't"; + credentials["passwd"] = "matter"; + credentials["cfg_srv_timeout"] = 0.0f; + + login.connect("login.bar.com", credentials); + + ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest"); + + // Get the mainloop eventpump, which needs a pinging in order to drive the + // SRV timeout. + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); + LLSD frame_event; + mainloop.post(frame_event); + + ensure_equals("SRV Failure", listener.lastEvent()["change"].asString(), "fail.login"); + } } |