summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llui/llfloater.cpp77
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/settings.xml26
-rw-r--r--indra/newview/llagentwearables.cpp7
-rw-r--r--indra/newview/llappearancemgr.cpp21
-rw-r--r--indra/newview/llappearancemgr.h1
-rw-r--r--indra/newview/llavataractions.cpp2
-rw-r--r--indra/newview/llbottomtray.cpp36
-rw-r--r--indra/newview/llbottomtray.h7
-rw-r--r--indra/newview/llimpanel.cpp7
-rw-r--r--indra/newview/llimview.cpp107
-rw-r--r--indra/newview/llimview.h22
-rw-r--r--indra/newview/llinventorymodel.cpp562
-rw-r--r--indra/newview/llinventorymodel.h259
-rw-r--r--indra/newview/llinventoryobserver.cpp564
-rw-r--r--indra/newview/llinventoryobserver.h249
-rw-r--r--indra/newview/llinventorypanel.cpp24
-rw-r--r--indra/newview/llinventorypanel.h2
-rw-r--r--indra/newview/lllogininstance.cpp3
-rw-r--r--indra/newview/llnearbychatbar.cpp30
-rw-r--r--indra/newview/llnearbychatbar.h10
-rw-r--r--indra/newview/llpanelimcontrolpanel.cpp13
-rw-r--r--indra/newview/llpanelmaininventory.cpp5
-rw-r--r--indra/newview/llpanelpeople.cpp2
-rw-r--r--indra/newview/llspatialpartition.cpp2
-rw-r--r--indra/newview/llspeakbutton.cpp10
-rw-r--r--indra/newview/llspeakbutton.h5
-rw-r--r--indra/newview/llstartup.cpp6
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp6
-rw-r--r--indra/newview/llviewertexture.cpp16
-rw-r--r--indra/newview/llviewertexture.h17
-rw-r--r--indra/newview/llviewertexturelist.cpp26
-rw-r--r--indra/newview/llviewertexturelist.h14
-rw-r--r--indra/newview/llvoicechannel.cpp15
-rw-r--r--indra/newview/llvoicechannel.h1
-rw-r--r--indra/newview/llvoiceclient.cpp4
-rw-r--r--indra/newview/llworldmipmap.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_incoming_call.xml40
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_outgoing_call.xml69
-rw-r--r--indra/newview/skins/default/xui/en/floater_tos.xml18
-rw-r--r--indra/newview/skins/default/xui/en/panel_bottomtray.xml6
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp1
-rw-r--r--indra/viewer_components/login/lllogin.cpp29
-rw-r--r--indra/viewer_components/login/tests/lllogin_test.cpp37
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");
+ }
}