summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rwxr-xr-xindra/newview/llconversationview.cpp20
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.cpp78
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.h9
-rw-r--r--indra/newview/llfloaterconversationpreview.cpp8
-rw-r--r--indra/newview/llfloaterimcontainer.cpp33
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp39
-rw-r--r--indra/newview/llfloaterimsessiontab.h5
-rw-r--r--indra/newview/llimview.cpp2
-rw-r--r--indra/newview/llinventoryfunctions.cpp27
-rw-r--r--indra/newview/llinventoryfunctions.h1
-rw-r--r--indra/newview/llnotificationstorage.cpp93
-rw-r--r--indra/newview/llpaneloutfitedit.cpp2
-rw-r--r--indra/newview/llspeakers.cpp67
-rw-r--r--indra/newview/llspeakers.h1
-rw-r--r--indra/newview/llviewermenu.cpp16
-rwxr-xr-xindra/newview/llviewermessage.cpp143
-rwxr-xr-xindra/newview/llviewerwindow.cpp18
-rw-r--r--indra/newview/llvoicevivox.cpp100
-rw-r--r--indra/newview/llvoicevivox.h3
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_effect.xml3
-rw-r--r--indra/newview/skins/default/xui/en/menu_im_session_showmodes.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_participant_view.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml39
23 files changed, 462 insertions, 284 deletions
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index bdd5dfc51a..5ff013ccc4 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -204,14 +204,6 @@ void LLConversationViewSession::draw()
const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
- // we don't draw the open folder arrow in minimized mode
- if (mHasArrow && !mCollapsedMode)
- {
- // update the rotation angle of open folder arrow
- updateLabelRotation();
- drawOpenFolderArrow(default_params, sFgColor);
- }
-
// Indicate that flash can start (moot operation if already started, done or not flashing)
startFlashing();
@@ -234,7 +226,15 @@ void LLConversationViewSession::draw()
(*iit)->setVisible(draw_children);
}
- refresh();
+ // we don't draw the open folder arrow in minimized mode
+ if (mHasArrow && !mCollapsedMode)
+ {
+ // update the rotation angle of open folder arrow
+ updateLabelRotation();
+ drawOpenFolderArrow(default_params, sFgColor);
+ }
+
+ refresh();
LLView::draw();
}
@@ -250,7 +250,7 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )
if(result && getRoot()->getCurSelectedItem() == this)
{
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
- im_container->clearAllFlashStates();
+ im_container->flashConversationItemWidget(session_id,false);
im_container->selectConversationPair(session_id, false);
im_container->collapseMessagesPane(false);
}
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index 42b455c1ce..15c42e8285 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -43,15 +43,17 @@
#include "lluuid.h"
static const F32 DND_TIMER = 3.0;
+const char * LLDoNotDisturbNotificationStorage::toastName = "IMToast";
+const char * LLDoNotDisturbNotificationStorage::offerName = "UserGiveItem";
LLDoNotDisturbNotificationStorageTimer::LLDoNotDisturbNotificationStorageTimer() : LLEventTimer(DND_TIMER)
{
- mEventTimer.start();
+
}
LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer()
{
- mEventTimer.stop();
+
}
BOOL LLDoNotDisturbNotificationStorageTimer::tick()
@@ -71,6 +73,8 @@ LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()
, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"))
, mDirty(false)
{
+ nameToPayloadParameterMap[toastName] = "SESSION_ID";
+ nameToPayloadParameterMap[offerName] = "object_id";
}
LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage()
@@ -152,27 +156,27 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
std::string notificationName = notification_params["name"];
LLNotificationPtr notification = instance.find(notificationID);
- if(notificationName == "IMToast")
+ if(notificationName == toastName)
{
imToastExists = true;
}
//New notification needs to be added
- notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true));
- LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]);
- if (responder == NULL)
- {
- LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '"
- << notification->getType() << "'" << LL_ENDL;
- }
- else
- {
- LLNotificationResponderPtr responderPtr(responder);
- notification->setResponseFunctor(responderPtr);
- }
-
- instance.add(notification);
+ notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true));
+ LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]);
+ if (responder == NULL)
+ {
+ LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '"
+ << notification->getType() << "'" << LL_ENDL;
}
+ else
+ {
+ LLNotificationResponderPtr responderPtr(responder);
+ notification->setResponseFunctor(responderPtr);
+ }
+
+ instance.add(notification);
+ }
if(imToastExists)
{
@@ -200,7 +204,7 @@ void LLDoNotDisturbNotificationStorage::updateNotifications()
LLNotificationPtr notification = it->second;
std::string notificationName = notification->getName();
- if(notificationName == "IMToast")
+ if(notificationName == toastName)
{
imToastExists = true;
}
@@ -221,9 +225,9 @@ void LLDoNotDisturbNotificationStorage::updateNotifications()
//When exit DND mode, write empty notifications file
if(commChannel->getHistorySize())
{
- commChannel->clearHistory();
- saveNotifications();
-}
+ commChannel->clearHistory();
+ saveNotifications();
+ }
}
LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const
@@ -233,14 +237,16 @@ LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChan
return channelPtr;
}
-void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& session_id)
+void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, const LLUUID& id)
{
LLNotifications& instance = LLNotifications::instance();
LLNotificationChannelPtr channelPtr = getCommunicationChannel();
LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
LLNotificationPtr notification;
- LLSD substitutions;
- LLUUID notificationSessionID;
+ LLSD payload;
+ LLUUID notificationObjectID;
+ std::string notificationName;
+ std::string payloadVariable = nameToPayloadParameterMap[name];
LLCommunicationChannel::history_list_t::iterator it;
std::vector<LLCommunicationChannel::history_list_t::iterator> itemsToRemove;
@@ -250,27 +256,29 @@ void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& sessi
++it)
{
notification = it->second;
- substitutions = notification->getSubstitutions();
- notificationSessionID = substitutions["SESSION_ID"].asUUID();
+ payload = notification->getPayload();
+ notificationObjectID = payload[payloadVariable].asUUID();
+ notificationName = notification->getName();
- if(session_id == notificationSessionID)
+ if((notificationName == name)
+ && id == notificationObjectID)
{
itemsToRemove.push_back(it);
}
}
-
+
//Remove the notifications
if(itemsToRemove.size())
{
- while(itemsToRemove.size())
- {
- it = itemsToRemove.back();
- notification = it->second;
+ while(itemsToRemove.size())
+ {
+ it = itemsToRemove.back();
+ notification = it->second;
commChannel->removeItemFromHistory(notification);
- instance.cancel(notification);
- itemsToRemove.pop_back();
- }
+ instance.cancel(notification);
+ itemsToRemove.pop_back();
+ }
//Trigger saving of notifications to xml once all have been removed
saveNotifications();
}
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index fd03b71357..6e68b0d1be 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -42,9 +42,6 @@ public:
~LLDoNotDisturbNotificationStorageTimer();
public:
- void startTimer();
- void stopTimer();
- bool isRunning();
BOOL tick();
};
@@ -52,6 +49,9 @@ class LLDoNotDisturbNotificationStorage : public LLSingleton<LLDoNotDisturbNotif
{
LOG_CLASS(LLDoNotDisturbNotificationStorage);
public:
+ static const char * toastName;
+ static const char * offerName;
+
LLDoNotDisturbNotificationStorage();
~LLDoNotDisturbNotificationStorage();
@@ -61,7 +61,7 @@ public:
void saveNotifications();
void loadNotifications();
void updateNotifications();
- void removeIMNotification(const LLUUID& session_id);
+ void removeNotification(const char * name, const LLUUID& id);
protected:
@@ -71,6 +71,7 @@ private:
LLNotificationChannelPtr getCommunicationChannel() const;
bool onChannelChanged(const LLSD& pPayload);
+ std::map<std::string, std::string> nameToPayloadParameterMap;
};
#endif // LL_LLDONOTDISTURBNOTIFICATIONSTORAGE_H
diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp
index c93181c0a1..48e0caa0ce 100644
--- a/indra/newview/llfloaterconversationpreview.cpp
+++ b/indra/newview/llfloaterconversationpreview.cpp
@@ -152,7 +152,13 @@ void LLFloaterConversationPreview::showHistory()
chat.mSourceType = LLFloaterIMNearbyChat::isWordsName(from) ? CHAT_SOURCE_UNKNOWN : CHAT_SOURCE_OBJECT;
}
- mChatHistory->appendMessage(chat);
+ LLSD chat_args;
+ chat_args["use_plain_text_chat_history"] =
+ gSavedSettings.getBOOL("PlainTextChatHistory");
+ chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime");
+ chat_args["show_names_for_p2p_conv"] = gSavedSettings.getBOOL("IMShowNamesForP2PConv");
+
+ mChatHistory->appendMessage(chat,chat_args);
}
}
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 062a92b520..ff6234fa27 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -431,7 +431,9 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
return false;
}
LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id);
- LLFloaterIMSessionTab *conversation_floater = (session_id.isNull() ? (LLFloaterIMSessionTab*)(LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat")) : (LLFloaterIMSessionTab*)(LLFloaterIMSession::findInstance(session_id)));
+ LLFloaterIMSessionTab *conversation_floater = (session_id.isNull() ?
+ (LLFloaterIMSessionTab*)(LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))
+ : (LLFloaterIMSessionTab*)(LLFloaterIMSession::findInstance(session_id)));
if (type == "remove_participant")
{
@@ -813,6 +815,10 @@ void LLFloaterIMContainer::onCustomAction(const LLSD& userdata)
floater_prefp->selectPrivacyPanel();
}
}
+ if ("Translating.Toggle" == command)
+ {
+ gSavedSettings.setBOOL("TranslateChat", !gSavedSettings.getBOOL("TranslateChat"));
+ }
}
BOOL LLFloaterIMContainer::isActionChecked(const LLSD& userdata)
@@ -843,7 +849,14 @@ BOOL LLFloaterIMContainer::isActionChecked(const LLSD& userdata)
{
return (order.getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE);
}
-
+ if ("Translating.Enabled" == command)
+ {
+ return gSavedPerAccountSettings.getBOOL("TranslatingEnabled");
+ }
+ if ("Translating.On" == command)
+ {
+ return gSavedSettings.getBOOL("TranslateChat");
+ }
return FALSE;
}
@@ -1299,11 +1312,14 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
if (widget && widget->getParentFolder())
{
widget->getParentFolder()->setSelection(widget, FALSE, FALSE);
- if(gAgent.isDoNotDisturb())
- {
- LLDoNotDisturbNotificationStorage::getInstance()->removeIMNotification(session_id);
- }
}
+
+ //When in DND mode, remove stored IM notifications
+ //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal
+ if(gAgent.isDoNotDisturb() && session_id.notNull())
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, session_id);
+ }
}
/* floater processing */
@@ -1324,11 +1340,6 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
// Switch to the conversation floater that is being selected
selectFloater(session_floater);
}
-
- if(gAgent.isDoNotDisturb())
- {
- LLDoNotDisturbNotificationStorage::getInstance()->removeIMNotification(session_id);
- }
}
// Set the focus on the selected floater
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 06a79836db..37404ab716 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -60,6 +60,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
, mInputEditorTopPad(0)
, mRefreshTimer(new LLTimer())
, mIsHostAttached(false)
+ , mHasVisibleBeenInitialized(false)
{
setAutoFocus(FALSE);
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
@@ -72,12 +73,6 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
boost::bind(&LLFloaterIMSessionTab::onIMShowModesMenuItemCheck, this, _2));
mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.Enable",
boost::bind(&LLFloaterIMSessionTab::onIMShowModesMenuItemEnable, this, _2));
- mEnableCallbackRegistrar.add("Translating.Enabled",
- boost::bind(&LLFloaterIMSessionTab::isTranslatingEnabled, this, _2));
- mEnableCallbackRegistrar.add("Translating.On",
- boost::bind(&LLFloaterIMSessionTab::isTranslationOn, this, _2));
- mCommitCallbackRegistrar.add("Translating.Toggle",
- boost::bind(&LLFloaterIMSessionTab::toggleTranslation, this, _2));
// Right click menu handling
mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2));
@@ -88,13 +83,6 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
{
delete mRefreshTimer;
-
- // Select Nearby Chat session
- LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("im_container");
- if (container)
- {
- container->selectConversationPair(LLUUID(NULL), true);
- }
}
//static
@@ -133,12 +121,14 @@ LLFloaterIMSessionTab* LLFloaterIMSessionTab::getConversation(const LLUUID& uuid
void LLFloaterIMSessionTab::setVisible(BOOL visible)
{
- LLTransientDockableFloater::setVisible(visible);
-
- if(visible)
+ if(visible && !mHasVisibleBeenInitialized)
{
- LLFloaterIMSessionTab::addToHost(mSessionID);
+ mHasVisibleBeenInitialized = true;
+ LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")->setVisible(true);
+ LLFloaterIMSessionTab::addToHost(mSessionID);
}
+
+ LLTransientDockableFloater::setVisible(visible);
}
/*virtual*/
@@ -558,11 +548,6 @@ void LLFloaterIMSessionTab::onIMSessionMenuItemClicked(const LLSD& userdata)
LLFloaterIMSessionTab::processChatHistoryStyleUpdate();
}
-void LLFloaterIMSessionTab::toggleTranslation(const LLSD& userdata)
-{
- gSavedSettings.setBOOL("TranslateChat", !gSavedSettings.getBOOL("TranslateChat"));
-}
-
bool LLFloaterIMSessionTab::onIMCompactExpandedMenuItemCheck(const LLSD& userdata)
{
std::string item = userdata.asString();
@@ -586,16 +571,6 @@ bool LLFloaterIMSessionTab::onIMShowModesMenuItemEnable(const LLSD& userdata)
return (plain_text && (is_not_names || mIsP2PChat));
}
-bool LLFloaterIMSessionTab::isTranslatingEnabled(const LLSD& userdata)
-{
- return gSavedPerAccountSettings.getBOOL("TranslatingEnabled");
-}
-
-bool LLFloaterIMSessionTab::isTranslationOn(const LLSD& userdata)
-{
- return gSavedSettings.getBOOL("TranslateChat");
-}
-
void LLFloaterIMSessionTab::hideOrShowTitle()
{
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index 05da0f98bc..beaffc14a6 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -109,12 +109,8 @@ protected:
//
bool onIMShowModesMenuItemCheck(const LLSD& userdata);
bool onIMShowModesMenuItemEnable(const LLSD& userdata);
- bool isTranslatingEnabled(const LLSD& userdata);
- bool isTranslationOn(const LLSD& userdata);
static void onSlide(LLFloaterIMSessionTab *self);
- void toggleTranslation(const LLSD& userdata);
-
// refresh a visual state of the Call button
void updateCallBtnState(bool callIsActive);
@@ -186,6 +182,7 @@ private:
bool checkIfTornOff();
bool mIsHostAttached;
+ bool mHasVisibleBeenInitialized;
LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
};
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index d0a8dfc0c8..cb03c1d234 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -144,7 +144,7 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,
args["FROM"] = av_name.getCompleteName();
args["FROM_ID"] = msg["from_id"];
args["SESSION_ID"] = msg["session_id"];
- LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID()));
+ LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID()));
}
void on_new_message(const LLSD& msg)
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 6474d56414..ad0a730dd1 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -46,6 +46,7 @@
#include "llappearancemgr.h"
#include "llappviewer.h"
#include "llclipboard.h"
+#include "lldonotdisturbnotificationstorage.h"
#include "llfloaterinventory.h"
#include "llfloatersidepanelcontainer.h"
#include "llfocusmgr.h"
@@ -1132,11 +1133,37 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
}
+void LLInventoryAction::removeItemFromDND(LLFolderView* root)
+{
+ if(gAgent.isDoNotDisturb())
+ {
+ //Get selected items
+ LLFolderView::selected_items_t selectedItems = root->getSelectedItems();
+ LLFolderViewModelItemInventory * viewModel = NULL;
+
+ //If user is in DND and deletes item, make sure the notification is not displayed by removing the notification
+ //from DND history and .xml file. Once this is done, upon exit of DND mode the item deleted will not show a notification.
+ for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it)
+ {
+ viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem());
+
+ if(viewModel && viewModel->getUUID().notNull())
+ {
+ //Will remove the item offer notification
+ LLDoNotDisturbNotificationStorage::instance().removeNotification(LLDoNotDisturbNotificationStorage::offerName, viewModel->getUUID());
+ }
+ }
+ }
+}
+
void LLInventoryAction::onItemsRemovalConfirmation( const LLSD& notification, const LLSD& response, LLFolderView* root )
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
+ //Need to remove item from DND before item is removed from root folder view
+ //because once removed from root folder view the item is no longer a selected item
+ removeItemFromDND(root);
root->removeSelectedItems();
}
}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 11fc17ce9b..f1066a4dc9 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -433,6 +433,7 @@ struct LLInventoryAction
static void doToSelected(class LLInventoryModel* model, class LLFolderView* root, const std::string& action);
static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLFolderView* root);
+ static void removeItemFromDND(LLFolderView* root);
};
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
index 4c5b7cc198..b6184f09bf 100644
--- a/indra/newview/llnotificationstorage.cpp
+++ b/indra/newview/llnotificationstorage.cpp
@@ -38,30 +38,43 @@
#include "llsd.h"
#include "llsdserialize.h"
#include "llsingleton.h"
-#include "llviewermessage.h"
+#include "llregistry.h"
+#include "llviewermessage.h"
+typedef boost::function<LLNotificationResponderInterface * (const LLSD& pParams)> responder_constructor_t;
-class LLResponderRegistry : public LLSingleton<LLResponderRegistry>
+class LLResponderRegistry : public LLRegistrySingleton<std::string, responder_constructor_t, LLResponderRegistry>
{
-public:
- LLResponderRegistry();
- ~LLResponderRegistry();
-
- LLNotificationResponderInterface* createResponder(const std::string& pNotificationName, const LLSD& pParams);
-
-protected:
-
-private:
- template<typename RESPONDER_TYPE> static LLNotificationResponderInterface* create(const LLSD& pParams);
-
- typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
-
- void add(const std::string& pNotificationName, const responder_constructor_t& pConstructor);
-
- typedef std::map<std::string, responder_constructor_t> build_map_t;
- build_map_t mBuildMap;
+ public:
+ template<typename RESPONDER_TYPE> static LLNotificationResponderInterface * create(const LLSD& pParams);
+ LLNotificationResponderInterface * createResponder(const std::string& pNotificationName, const LLSD& pParams);
};
+template<typename RESPONDER_TYPE> LLNotificationResponderInterface * LLResponderRegistry::create(const LLSD& pParams)
+{
+ RESPONDER_TYPE* responder = new RESPONDER_TYPE();
+ responder->fromLLSD(pParams);
+ return responder;
+}
+
+
+LLNotificationResponderInterface * LLResponderRegistry::createResponder(const std::string& pNotificationName, const LLSD& pParams)
+{
+ responder_constructor_t * factoryFunc = (LLResponderRegistry::getValue(pNotificationName));
+
+ if(factoryFunc)
+ {
+ return (*factoryFunc)(pParams);
+ }
+
+ return NULL;
+}
+
+LLResponderRegistry::StaticRegistrar sRegisterObjectGiveItem("ObjectGiveItem", &LLResponderRegistry::create<LLOfferInfo>);
+LLResponderRegistry::StaticRegistrar sRegisterUserGiveItem("UserGiveItem", &LLResponderRegistry::create<LLOfferInfo>);
+LLResponderRegistry::StaticRegistrar sRegisterOfferInfo("offer_info", &LLResponderRegistry::create<LLOfferInfo>);
+
+
LLNotificationStorage::LLNotificationStorage(std::string pFileName)
: mFileName(pFileName)
{
@@ -116,47 +129,7 @@ bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const
return didFileRead;
}
-LLNotificationResponderInterface* LLNotificationStorage::createResponder(const std::string& pNotificationName, const LLSD& pParams) const
+LLNotificationResponderInterface * LLNotificationStorage::createResponder(const std::string& pNotificationName, const LLSD& pParams) const
{
return LLResponderRegistry::getInstance()->createResponder(pNotificationName, pParams);
}
-
-LLResponderRegistry::LLResponderRegistry()
- : LLSingleton<LLResponderRegistry>()
- , mBuildMap()
-{
- add("ObjectGiveItem", &create<LLOfferInfo>);
- add("UserGiveItem", &create<LLOfferInfo>);
- add("offer_info", &create<LLOfferInfo>);
-}
-
-LLResponderRegistry::~LLResponderRegistry()
-{
-}
-
-LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& pNotificationName, const LLSD& pParams)
-{
- build_map_t::const_iterator it = mBuildMap.find(pNotificationName);
- if(mBuildMap.end() == it)
- {
- return NULL;
- }
- responder_constructor_t ctr = it->second;
- return ctr(pParams);
-}
-
-template<typename RESPONDER_TYPE> LLNotificationResponderInterface* LLResponderRegistry::create(const LLSD& pParams)
-{
- RESPONDER_TYPE* responder = new RESPONDER_TYPE();
- responder->fromLLSD(pParams);
- return responder;
-}
-
-void LLResponderRegistry::add(const std::string& pNotificationName, const responder_constructor_t& pConstructor)
-{
- if (mBuildMap.find(pNotificationName) != mBuildMap.end())
- {
- LL_ERRS("LLResponderRegistry") << "Responder is already registered : " << pNotificationName << LL_ENDL;
- }
- mBuildMap.insert(std::make_pair<std::string, responder_constructor_t>(pNotificationName, pConstructor));
-}
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index d690a18477..f5db98f831 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -169,7 +169,7 @@ public:
return menu;
}
-
+
private:
static void onCreate(const LLSD& param)
{
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 88f29d7587..a2d8874cea 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -31,6 +31,7 @@
#include "llagent.h"
#include "llappviewer.h"
#include "llimview.h"
+#include "llgroupmgr.h"
#include "llsdutil.h"
#include "lluicolortable.h"
#include "llviewerobjectlist.h"
@@ -305,9 +306,10 @@ private:
//
LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
- mVoiceChannel(channelp)
-, mVoiceModerated(false)
-, mModerateModeHandledFirstTime(false)
+ mVoiceChannel(channelp),
+ mVoiceModerated(false),
+ mModerateModeHandledFirstTime(false),
+ mSpeakerListUpdated(false)
{
static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0);
@@ -321,7 +323,11 @@ LLSpeakerMgr::~LLSpeakerMgr()
LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
{
- if (id.isNull()) return NULL;
+ LLUUID session_id = getSessionID();
+ if (id.isNull() || (id == session_id))
+ {
+ return NULL;
+ }
LLPointer<LLSpeaker> speakerp;
if (mSpeakers.find(id) == mSpeakers.end())
@@ -525,23 +531,60 @@ void LLSpeakerMgr::updateSpeakerList()
{
// If not, check if the list is empty, except if it's Nearby Chat (session_id NULL).
LLUUID session_id = getSessionID();
- if ((mSpeakers.size() == 0) && (!session_id.isNull()))
+ if (!session_id.isNull() && !mSpeakerListUpdated)
{
- // If the list is empty, we update it with whatever was used to initiate the call so that it doesn't stay empty too long.
- // *TODO: Fix the server side code that sometimes forgets to send back the list of agents after a chat started
+ // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long.
+ // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started.
// (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply)
LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
- for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it)
+ if (session->isGroupSessionType() && (mSpeakers.size() <= 1))
+ {
+ // For groups, we need to hit the group manager.
+ // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id);
+ if (!gdatap)
+ {
+ // Request the data the first time around
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id);
+ }
+ else if (gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
+ {
+ // Add group members when we get the complete list (note: can take a while before we get that list)
+ LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin();
+ while (member_it != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member = member_it->second;
+ // Add only the members who are online
+ if (member->getOnlineStatus() == "Online")
+ {
+ setSpeaker(member_it->first, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ }
+ ++member_it;
+ }
+ mSpeakerListUpdated = true;
+ }
+ }
+ else if (mSpeakers.size() == 0)
{
- // Add buddies if they are on line, add any other avatar.
- if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it))
+ // For all other session type (ad-hoc, P2P, avaline), we use the initial participants targets list
+ for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it)
{
- setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ // Add buddies if they are on line, add any other avatar.
+ if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it))
+ {
+ setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ }
}
+ mSpeakerListUpdated = true;
+ }
+ else
+ {
+ // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server)
+ mSpeakerListUpdated = true;
}
}
}
- // Finally, always add the current agent (it has to be there no matter what...)
+ // Always add the current agent (it has to be there...). Will do nothing if already there.
setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
}
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 7d518fe07b..5f5095097e 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -263,6 +263,7 @@ protected:
typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
speaker_map_t mSpeakers;
+ bool mSpeakerListUpdated;
speaker_list_t mSpeakersSorted;
LLFrameTimer mSpeechTimer;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index a0aa639ac6..8b45c44ed0 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -108,6 +108,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerstats.h"
#include "llvoavatarself.h"
+#include "llvoicevivox.h"
#include "llworldmap.h"
#include "pipeline.h"
#include "llviewerjoystick.h"
@@ -8152,6 +8153,11 @@ public:
}
};
+void handle_voice_morphing_subscribe()
+{
+ LLWeb::loadURLExternal(LLTrans::getString("voice_morphing_url"));
+}
+
class LLToggleUIHints : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -8337,7 +8343,15 @@ void initialize_menus()
// Me > Movement
view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
-
+
+ // Communicate > Voice morphing > Subscribe...
+ commit.add("Communicate.VoiceMorphing.Subscribe", boost::bind(&handle_voice_morphing_subscribe));
+ LLVivoxVoiceClient * voice_clientp = LLVivoxVoiceClient::getInstance();
+ enable.add("Communicate.VoiceMorphing.NoVoiceMorphing.Check"
+ , boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, voice_clientp, "NoVoiceMorphing"));
+ commit.add("Communicate.VoiceMorphing.NoVoiceMorphing.Click"
+ , boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, voice_clientp, "NoVoiceMorphing"));
+
// World menu
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index db81e057de..d235ba5f96 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -189,70 +189,74 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
const LLSD& payload = notification["payload"];
LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID());
- // add friend to recent people list
- LLRecentPeople::instance().add(payload["from_id"]);
-
- switch(option)
- {
- case 0:
- {
- // accept
- LLAvatarTracker::formFriendship(payload["from_id"]);
-
- const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
-
- // This will also trigger an onlinenotification if the user is online
- msg->newMessageFast(_PREHASH_AcceptFriendship);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, fid);
- msg->sendReliable(LLHost(payload["sender"].asString()));
-
- LLSD payload = notification["payload"];
- LLNotificationsUtil::add("FriendshipAcceptedByMe",
- notification["substitutions"], payload);
- break;
- }
- case 1: // Decline
- {
- LLSD payload = notification["payload"];
- LLNotificationsUtil::add("FriendshipDeclinedByMe",
- notification["substitutions"], payload);
- }
- // fall-through
- case 2: // Send IM - decline and start IM session
- {
- // decline
- // We no longer notify other viewers, but we DO still send
- // the rejection to the simulator to delete the pending userop.
- msg->newMessageFast(_PREHASH_DeclineFriendship);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
- msg->sendReliable(LLHost(payload["sender"].asString()));
-
- // start IM session
- if(2 == option)
- {
- LLAvatarActions::startIM(payload["from_id"].asUUID());
- }
- }
- default:
- // close button probably, possibly timed out
- break;
- }
-
- LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm()));
- modified_form->setElementEnabled("Accept", false);
- modified_form->setElementEnabled("Decline", false);
- notification_ptr->updateForm(modified_form);
- notification_ptr->repost();
+ // this will be skipped if the user offering friendship is blocked
+ if (notification_ptr)
+ {
+ // add friend to recent people list
+ LLRecentPeople::instance().add(payload["from_id"]);
+
+ switch(option)
+ {
+ case 0:
+ {
+ // accept
+ LLAvatarTracker::formFriendship(payload["from_id"]);
+
+ const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+
+ // This will also trigger an onlinenotification if the user is online
+ msg->newMessageFast(_PREHASH_AcceptFriendship);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
+ msg->nextBlockFast(_PREHASH_FolderData);
+ msg->addUUIDFast(_PREHASH_FolderID, fid);
+ msg->sendReliable(LLHost(payload["sender"].asString()));
+
+ LLSD payload = notification["payload"];
+ LLNotificationsUtil::add("FriendshipAcceptedByMe",
+ notification["substitutions"], payload);
+ break;
+ }
+ case 1: // Decline
+ {
+ LLSD payload = notification["payload"];
+ LLNotificationsUtil::add("FriendshipDeclinedByMe",
+ notification["substitutions"], payload);
+ }
+ // fall-through
+ case 2: // Send IM - decline and start IM session
+ {
+ // decline
+ // We no longer notify other viewers, but we DO still send
+ // the rejection to the simulator to delete the pending userop.
+ msg->newMessageFast(_PREHASH_DeclineFriendship);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
+ msg->sendReliable(LLHost(payload["sender"].asString()));
+
+ // start IM session
+ if(2 == option)
+ {
+ LLAvatarActions::startIM(payload["from_id"].asUUID());
+ }
+ }
+ default:
+ // close button probably, possibly timed out
+ break;
+ }
+
+ LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm()));
+ modified_form->setElementEnabled("Accept", false);
+ modified_form->setElementEnabled("Decline", false);
+ notification_ptr->updateForm(modified_form);
+ notification_ptr->repost();
+ }
return false;
}
@@ -1618,12 +1622,6 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
{
opener = discard_agent_offer;
}
-
-
- if (gAgent.isDoNotDisturb() && (!mFromGroup && !mFromObject))
- {
- send_do_not_disturb_message(gMessageSystem, mFromID);
- }
if (modified_form != NULL)
{
@@ -1991,6 +1989,11 @@ void inventory_offer_handler(LLOfferInfo* info)
// In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
info->send_auto_receive_response();
+ if (gAgent.isDoNotDisturb())
+ {
+ send_do_not_disturb_message(gMessageSystem, info->mFromID);
+ }
+
// Inform user that there is a script floater via toast system
{
payload["give_inventory_notification"] = TRUE;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2d5634a41d..36ddf26c82 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2503,22 +2503,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
return TRUE;
}
- LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
+ LLFloater* focused_floaterp = gFloaterView->getFocusedFloater();
+ std::string focusedFloaterName = (focused_floaterp ? focused_floaterp->getInstanceName() : "");
- // Traverses up the hierarchy
if( keyboard_focus )
{
- if (nearby_chat)
- {
- LLChatEntry* chat_editor = nearby_chat->getChatBox();
-
- // arrow keys move avatar while chatting hack
- if (chat_editor && chat_editor->hasFocus())
+ if ((focusedFloaterName == "nearby_chat") || (focusedFloaterName == "im_container") || (focusedFloaterName == "impanel"))
{
- // If text field is empty, there's no point in trying to move
- // cursor with arrow keys, so allow movement
- if (chat_editor->getText().empty()
- || gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
+ if (gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
{
// let Control-Up and Control-Down through for chat line history,
if (!(key == KEY_UP && mask == MASK_CONTROL)
@@ -2540,7 +2532,6 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
break;
}
}
- }
}
}
@@ -2575,6 +2566,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
!keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
{
// Initialize nearby chat if it's missing
+ LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (!nearby_chat)
{
LLSD name("im_container");
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 5e121bbcee..f3342b7ff1 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -34,6 +34,7 @@
#include "llvoavatarself.h"
#include "llbufferstream.h"
#include "llfile.h"
+#include "llmenugl.h"
#ifdef LL_STANDALONE
# include "expat.h"
#else
@@ -70,6 +71,9 @@
#define USE_SESSION_GROUPS 0
+extern LLMenuBarGL* gMenuBarView;
+extern void handle_voice_morphing_subscribe();
+
const F32 VOLUME_SCALE_VIVOX = 0.01f;
const F32 SPEAKING_TIMEOUT = 1.f;
@@ -6739,10 +6743,106 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer)
mVoiceFontObservers.erase(observer);
}
+// method checks the item in VoiceMorphing menu for appropriate current voice font
+bool LLVivoxVoiceClient::onCheckVoiceEffect(const std::string& voice_effect_name)
+{
+ LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (NULL != effect_interfacep)
+ {
+ const LLUUID& currect_voice_effect_id = effect_interfacep->getVoiceEffect();
+
+ if (currect_voice_effect_id.isNull())
+ {
+ if (voice_effect_name == "NoVoiceMorphing")
+ {
+ return true;
+ }
+ }
+ else
+ {
+ const LLSD& voice_effect_props = effect_interfacep->getVoiceEffectProperties(currect_voice_effect_id);
+ if (voice_effect_props["name"].asString() == voice_effect_name)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// method changes voice font for selected VoiceMorphing menu item
+void LLVivoxVoiceClient::onClickVoiceEffect(const std::string& voice_effect_name)
+{
+ LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (NULL != effect_interfacep)
+ {
+ if (voice_effect_name == "NoVoiceMorphing")
+ {
+ effect_interfacep->setVoiceEffect(LLUUID());
+ return;
+ }
+ const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
+ if (!effect_list.empty())
+ {
+ for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
+ {
+ if (voice_effect_name == it->first)
+ {
+ effect_interfacep->setVoiceEffect(it->second);
+ return;
+ }
+ }
+ }
+ }
+}
+
+// it updates VoiceMorphing menu items in accordance with purchased properties
+void LLVivoxVoiceClient::updateVoiceMorphingMenu()
+{
+ if (mVoiceFontListDirty)
+ {
+ LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interfacep)
+ {
+ const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
+ if (!effect_list.empty())
+ {
+ LLMenuGL * voice_morphing_menup = gMenuBarView->findChildMenuByName("VoiceMorphing", TRUE);
+
+ if (NULL != voice_morphing_menup)
+ {
+ S32 items = voice_morphing_menup->getItemCount();
+ if (items > 0)
+ {
+ voice_morphing_menup->erase(1, items - 3, false);
+
+ S32 pos = 1;
+ for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
+ {
+ LLMenuItemCheckGL::Params p;
+ p.name = it->first;
+ p.label = it->first;
+ p.on_check.function(boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, this, it->first));
+ p.on_click.function(boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, this, it->first));
+ LLMenuItemCheckGL * voice_effect_itemp = LLUICtrlFactory::create<LLMenuItemCheckGL>(p);
+ voice_morphing_menup->insert(pos++, voice_effect_itemp, false);
+ }
+
+ voice_morphing_menup->needsArrange();
+ }
+ }
+ }
+ }
+ }
+}
+
void LLVivoxVoiceClient::notifyVoiceFontObservers()
{
LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL;
+ updateVoiceMorphingMenu();
+
for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
it != mVoiceFontObservers.end();
)
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 69f33df94b..574027de42 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -246,6 +246,8 @@ public:
//@}
+ bool onCheckVoiceEffect(const std::string& voice_effect_name);
+ void onClickVoiceEffect(const std::string& voice_effect_name);
protected:
//////////////////////
@@ -854,6 +856,7 @@ private:
void accountGetTemplateFontsSendMessage();
void sessionSetVoiceFontSendMessage(sessionState *session);
+ void updateVoiceMorphingMenu();
void notifyVoiceFontObservers();
typedef enum e_voice_font_type
diff --git a/indra/newview/skins/default/xui/en/floater_voice_effect.xml b/indra/newview/skins/default/xui/en/floater_voice_effect.xml
index 35cb2670d0..146c3d7e30 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_effect.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_effect.xml
@@ -5,12 +5,13 @@
height="500"
name="voice_effects"
help_topic="voice_effects"
- title="VOICE MORPHING"
+ title="VOICE MORPHING PREVIEW"
background_visible="true"
label="Places"
layout="topleft"
min_height="360"
min_width="200"
+ save_rect="true"
width="300">
<string name="no_voice_effect">
(No Voice Morph)
diff --git a/indra/newview/skins/default/xui/en/menu_im_session_showmodes.xml b/indra/newview/skins/default/xui/en/menu_im_session_showmodes.xml
index f2a8b39b04..b0adca0e0e 100644
--- a/indra/newview/skins/default/xui/en/menu_im_session_showmodes.xml
+++ b/indra/newview/skins/default/xui/en/menu_im_session_showmodes.xml
@@ -45,22 +45,5 @@
<menu_item_check.on_enable
function="IMSession.Menu.ShowModes.Enable"
parameter="IMShowNamesForP2PConv" />
- </menu_item_check>
- <menu_item_separator layout="topleft" />
- <menu_item_check name="Translate_chat" label="Translate chat">
- <menu_item_check.on_click
- function="Translating.Toggle" />
- <menu_item_check.on_check
- function="Translating.On" />
- <menu_item_check.on_enable
- function="Translating.Enabled" />
- </menu_item_check>
- <menu_item_check name="Translation_settings" label="Translation settings...">
- <menu_item_check.on_check
- function="Floater.Visible"
- parameter="prefs_translation" />
- <menu_item_check.on_click
- function="Floater.Toggle"
- parameter="prefs_translation" />
- </menu_item_check>
+ </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_participant_view.xml b/indra/newview/skins/default/xui/en/menu_participant_view.xml
index 2f2bafb95d..7ea87ee05c 100644
--- a/indra/newview/skins/default/xui/en/menu_participant_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_participant_view.xml
@@ -89,4 +89,24 @@
function="Avatar.EnableItem"
parameter="conversation_log" />
</menu_item_check>
+ <menu_item_separator layout="topleft" />
+ <menu_item_check name="Translate_chat" label="Translate Nearby chat">
+ <menu_item_check.on_click
+ function="IMFloaterContainer.Action"
+ parameter="Translating.Toggle" />
+ <menu_item_check.on_check
+ function="IMFloaterContainer.Check"
+ parameter="Translating.On" />
+ <menu_item_check.on_enable
+ function="IMFloaterContainer.Check"
+ parameter="Translating.Enabled" />
+ </menu_item_check>
+ <menu_item_check name="Translation_settings" label="Translation settings...">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="prefs_translation" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="prefs_translation" />
+ </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 8d5e3f0b5d..10fd8138d2 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -268,17 +268,36 @@
parameter="conversation" />
</menu_item_check>
<menu_item_separator/>
- <menu_item_check
- label="Voice morphing..."
- name="ShowVoice"
+ <menu
+ label="Voice morphing"
+ name="VoiceMorphing"
visibility_control="VoiceMorphingEnabled">
- <menu_item_check.on_check
- function="Floater.Visible"
- parameter="voice_effect" />
- <menu_item_check.on_click
- function="Floater.Toggle"
- parameter="voice_effect" />
- </menu_item_check>
+ <menu_item_check
+ label="No voice morphing"
+ name="NoVoiceMorphing">
+ <menu_item_check.on_check
+ function="Communicate.VoiceMorphing.NoVoiceMorphing.Check" />
+ <menu_item_check.on_click
+ function="Communicate.VoiceMorphing.NoVoiceMorphing.Click" />
+ </menu_item_check>
+ <menu_item_separator/>
+ <menu_item_check
+ label="Preview..."
+ name="Preview">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="voice_effect" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="voice_effect" />
+ </menu_item_check>
+ <menu_item_call
+ label="Subscribe..."
+ name="Subscribe">
+ <menu_item_call.on_click
+ function="Communicate.VoiceMorphing.Subscribe" />
+ </menu_item_call>
+ </menu>
<menu_item_check
label="Gestures..."
name="Gestures"