diff options
Diffstat (limited to 'indra/newview')
95 files changed, 2329 insertions, 711 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f3d399c616..a26aae3590 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -258,7 +258,6 @@ set(viewer_SOURCE_FILES llinventorymodel.cpp llinventoryobserver.cpp llinventorypanel.cpp - llinventorysubtreepanel.cpp lljoystickbutton.cpp lllandmarkactions.cpp lllandmarklist.cpp @@ -354,6 +353,7 @@ set(viewer_SOURCE_FILES llparticipantlist.cpp llpatchvertexarray.cpp llplacesinventorybridge.cpp + llplacesinventorypanel.cpp llpolymesh.cpp llpolymorph.cpp llpreview.cpp @@ -766,7 +766,6 @@ set(viewer_HEADER_FILES llinventorymodel.h llinventoryobserver.h llinventorypanel.h - llinventorysubtreepanel.h lljoystickbutton.h lllandmarkactions.h lllandmarklist.h @@ -858,6 +857,7 @@ set(viewer_HEADER_FILES llparticipantlist.h llpatchvertexarray.h llplacesinventorybridge.h + llplacesinventorypanel.h llpolymesh.h llpolymorph.h llpreview.h @@ -1397,12 +1397,29 @@ if (WINDOWS) # be met. I'm looking forward to a source-code split-up project next year that will address this kind of thing. # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py # and have the build deps get tracked *please* tell me about it. + + if(LLKDU_LIBRARY) + # Configure a var for llkdu which may not exist for all builds. + set(LLKDU_DLL_SOURCE ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llkdu.dll) + endif(LLKDU_LIBRARY) + + if(USE_GOOGLE_PERFTOOLS) + # Configure a var for tcmalloc location, if used. + # Note the need to specify multiple names explicitly. + set(GOOGLE_PERF_TOOLS_SOURCE + ${SHARED_LIB_STAGING_DIR}/Release/libtcmalloc_minimal.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll + ${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll + ) + endif(USE_GOOGLE_PERFTOOLS) + + set(COPY_INPUT_DEPENDECIES # The following commented dependencies are determined at variably at build time. Can't do this here. - #llkdu.dll => llkdu.dll #${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll ${CMAKE_SOURCE_DIR}/../etc/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg + ${LLKDU_DLL_SOURCE} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llcommon.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll @@ -1426,6 +1443,7 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/zlib1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxplatform.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxoal.dll + ${GOOGLE_PERF_TOOLS_SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt ${CMAKE_CURRENT_SOURCE_DIR}/dbghelp.dll @@ -1501,7 +1519,7 @@ if (WINDOWS) if(LLKDU_LIBRARY) # kdu may not exist! - add_dependencies(${VIEWER_BINARY_NAME} llkdu) + add_dependencies(copy_w_viewer_manifest llkdu) endif(LLKDU_LIBRARY) if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 455c3587ff..ba78d80ad1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3585,7 +3585,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>http://int.searchwww-phx0.damballah.lindenlab.com/viewer/[CATEGORY]?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]</string> + <string>http://int.searchwww-phx0.damballah.lindenlab.com/viewer/[CATEGORY]?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]</string> </map> <key>HighResSnapshot</key> <map> @@ -10378,6 +10378,17 @@ <key>Value</key> <string>Default</string> </map> + <key>VoiceParticipantLeftRemoveDelay</key> + <map> + <key>Comment</key> + <string>Timeout to remove participants who has left Voice chat from the list in Voice Controls Panel</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>10</integer> + </map> <key>VoicePort</key> <map> <key>Comment</key> diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index 5c5c4e5b3c..cc8f6780e3 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -157,7 +157,7 @@ Intel Bear Lake .*Intel.*Bear Lake.* 0 0 Intel Broadwater .*Intel.*Broadwater.* 0 0 Intel Brookdale .*Intel.*Brookdale.* 0 0 Intel Cantiga .*Intel.*Cantiga.* 0 0 -Intel Eaglelake .*Intel.*Eaglelake.* 0 0 +Intel Eaglelake .*Intel.*Eaglelake.* 0 1 Intel Montara .*Intel.*Montara.* 0 0 Intel Springdale .*Intel.*Springdale.* 0 0 Matrox .*Matrox.* 0 0 diff --git a/indra/newview/linux_tools/register_secondlifeprotocol.sh b/indra/newview/linux_tools/register_secondlifeprotocol.sh index c7b4d55461..16e73cb854 100755 --- a/indra/newview/linux_tools/register_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/register_secondlifeprotocol.sh @@ -22,13 +22,12 @@ else fi # Register handler for KDE-aware apps -if [ -z "$KDEHOME" ]; then - KDEHOME=~/.kde -fi -LLKDEPROTDIR=${KDEHOME}/share/services -if [ -d "$LLKDEPROTDIR" ]; then - LLKDEPROTFILE=${LLKDEPROTDIR}/secondlife.protocol - cat > ${LLKDEPROTFILE} <<EOF || echo Warning: Did not register secondlife:// handler with KDE: Could not write ${LLKDEPROTFILE} +for LLKDECONFIG in kde-config kde4-config; do + if [ `which $LLKDECONFIG` ]; then + LLKDEPROTODIR=`$LLKDECONFIG --path services | cut -d ':' -f 1` + if [ -d "$LLKDEPROTODIR" ]; then + LLKDEPROTOFILE=${LLKDEPROTODIR}/secondlife.protocol + cat > ${LLKDEPROTOFILE} <<EOF || echo Warning: Did not register secondlife:// handler with KDE: Could not write ${LLKDEPROTOFILE} [Protocol] exec=${HANDLER} '%u' protocol=secondlife @@ -41,6 +40,9 @@ writing=false makedir=false deleting=false EOF -else - echo Warning: Did not register secondlife:// handler with KDE: Directory $LLKDEPROTDIR does not exist. -fi + else + echo Warning: Did not register secondlife:// handler with KDE: Directory $LLKDEPROTODIR does not exist. + fi + fi +done + diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 651c66d0a7..2a8c55e5db 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -243,7 +243,6 @@ void LLAvatarActions::startAdhocCall(const std::vector<LLUUID>& ids) return; } - // start the call once the session has fully initialized gIMMgr->autoStartCallOnStartup(session_id); make_ui_sound("UISndStartIM"); diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 5317cf2cd0..b3ef6464f6 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -51,6 +51,12 @@ static const F32 LIT_UPDATE_PERIOD = 5; // Used to limit time spent for avatar list update per frame. static const unsigned ADD_LIMIT = 50; +bool LLAvatarList::contains(const LLUUID& id) +{ + const uuid_vector_t& ids = getIDs(); + return std::find(ids.begin(), ids.end(), id) != ids.end(); +} + void LLAvatarList::toggleIcons() { // Save the new value for new items to use. diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index e913be0f62..0d2ce884ae 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -75,6 +75,7 @@ public: void setNameFilter(const std::string& filter); void setDirty(bool val = true) { mDirty = val; } uuid_vector_t& getIDs() { return mIDs; } + bool contains(const LLUUID& id); void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; } diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index c8544bc3fb..8bc11b0c1c 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -158,7 +158,6 @@ void LLAvatarListItem::changed(U32 mask) void LLAvatarListItem::setOnline(bool online) { // *FIX: setName() overrides font style set by setOnline(). Not an issue ATM. - // *TODO: Make the colors configurable via XUI. if (mOnlineStatus != E_UNKNOWN && (bool) mOnlineStatus == online) return; @@ -166,11 +165,7 @@ void LLAvatarListItem::setOnline(bool online) mOnlineStatus = (EOnlineStatus) online; // Change avatar name font style depending on the new online status. - mAvatarNameStyle.color = online ? LLColor4::white : LLColor4::grey; - setNameInternal(mAvatarName->getText(), mHighlihtSubstring); - - // Make the icon fade if the avatar goes offline. - mAvatarIcon->setColor(online ? LLColor4::white : LLColor4::smoke); + setStyle(online ? IS_ONLINE : IS_OFFLINE); } void LLAvatarListItem::setName(const std::string& name) @@ -183,28 +178,21 @@ void LLAvatarListItem::setHighlight(const std::string& highlight) setNameInternal(mAvatarName->getText(), mHighlihtSubstring = highlight); } -void LLAvatarListItem::setStyle(const LLStyle::Params& new_style) +void LLAvatarListItem::setStyle(EItemStyle item_style) { -// LLTextUtil::textboxSetHighlightedVal(mAvatarName, mAvatarNameStyle = new_style); - - // Active group should be bold. - LLFontDescriptor new_desc(mAvatarName->getDefaultFont()->getFontDesc()); + item_style_map_t& item_styles_params_map = getItemStylesParams(); - new_desc.setStyle(new_style.font()->getFontDesc().getStyle()); - // *NOTE dzaporozhan - // On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font - // is predefined as bold (SansSerifSmallBold, for example) -// new_desc.setStyle(active ? LLFontGL::BOLD : LLFontGL::NORMAL); - LLFontGL* new_font = LLFontGL::getFont(new_desc); - -// - mAvatarNameStyle.font = new_font; + mAvatarNameStyle = item_styles_params_map[item_style]; // *NOTE: You cannot set the style on a text box anymore, you must // rebuild the text. This will cause problems if the text contains // hyperlinks, as their styles will be wrong. - mAvatarName->setText(mAvatarName->getText(), mAvatarNameStyle/* = new_style*/); + setNameInternal(mAvatarName->getText(), mHighlihtSubstring); + + icon_color_map_t& item_icon_color_map = getItemIconColorMap(); + mAvatarIcon->setColor(item_icon_color_map[item_style]); } + void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes) { if (mAvatarId.notNull()) @@ -418,3 +406,90 @@ std::string LLAvatarListItem::formatSeconds(U32 secs) args["[COUNT]"] = llformat("%u", count); return getString(fmt, args); } + +// static +LLAvatarListItem::item_style_map_t& LLAvatarListItem::getItemStylesParams() +{ + static item_style_map_t item_styles_params_map; + if (!item_styles_params_map.empty()) return item_styles_params_map; + + LLPanel::Params params = LLUICtrlFactory::getDefaultParams<LLPanel>(); + LLPanel* params_panel = LLUICtrlFactory::create<LLPanel>(params); + + BOOL sucsess = LLUICtrlFactory::instance().buildPanel(params_panel, "panel_avatar_list_item_params.xml"); + + if (sucsess) + { + + item_styles_params_map.insert( + std::make_pair(IS_DEFAULT, + params_panel->getChild<LLTextBox>("default_style")->getDefaultStyle())); + + item_styles_params_map.insert( + std::make_pair(IS_VOICE_INVITED, + params_panel->getChild<LLTextBox>("voice_call_invited_style")->getDefaultStyle())); + + item_styles_params_map.insert( + std::make_pair(IS_VOICE_JOINED, + params_panel->getChild<LLTextBox>("voice_call_joined_style")->getDefaultStyle())); + + item_styles_params_map.insert( + std::make_pair(IS_VOICE_LEFT, + params_panel->getChild<LLTextBox>("voice_call_left_style")->getDefaultStyle())); + + item_styles_params_map.insert( + std::make_pair(IS_ONLINE, + params_panel->getChild<LLTextBox>("online_style")->getDefaultStyle())); + + item_styles_params_map.insert( + std::make_pair(IS_OFFLINE, + params_panel->getChild<LLTextBox>("offline_style")->getDefaultStyle())); + } + else + { + item_styles_params_map.insert(std::make_pair(IS_DEFAULT, LLStyle::Params())); + item_styles_params_map.insert(std::make_pair(IS_VOICE_INVITED, LLStyle::Params())); + item_styles_params_map.insert(std::make_pair(IS_VOICE_JOINED, LLStyle::Params())); + item_styles_params_map.insert(std::make_pair(IS_VOICE_LEFT, LLStyle::Params())); + item_styles_params_map.insert(std::make_pair(IS_ONLINE, LLStyle::Params())); + item_styles_params_map.insert(std::make_pair(IS_OFFLINE, LLStyle::Params())); + } + if (params_panel) params_panel->die(); + + return item_styles_params_map; +} + +// static +LLAvatarListItem::icon_color_map_t& LLAvatarListItem::getItemIconColorMap() +{ + static icon_color_map_t item_icon_color_map; + if (!item_icon_color_map.empty()) return item_icon_color_map; + + item_icon_color_map.insert( + std::make_pair(IS_DEFAULT, + LLUIColorTable::instance().getColor("AvatarListItemIconDefaultColor", LLColor4::white))); + + item_icon_color_map.insert( + std::make_pair(IS_VOICE_INVITED, + LLUIColorTable::instance().getColor("AvatarListItemIconVoiceInvitedColor", LLColor4::white))); + + item_icon_color_map.insert( + std::make_pair(IS_VOICE_JOINED, + LLUIColorTable::instance().getColor("AvatarListItemIconVoiceJoinedColor", LLColor4::white))); + + item_icon_color_map.insert( + std::make_pair(IS_VOICE_LEFT, + LLUIColorTable::instance().getColor("AvatarListItemIconVoiceLeftColor", LLColor4::white))); + + item_icon_color_map.insert( + std::make_pair(IS_ONLINE, + LLUIColorTable::instance().getColor("AvatarListItemIconOnlineColor", LLColor4::white))); + + item_icon_color_map.insert( + std::make_pair(IS_OFFLINE, + LLUIColorTable::instance().getColor("AvatarListItemIconOfflineColor", LLColor4::white))); + + return item_icon_color_map; +} + +// EOF diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 0e058f75db..79303b55cc 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -46,6 +46,15 @@ class LLAvatarIconCtrl; class LLAvatarListItem : public LLPanel, public LLFriendObserver { public: + typedef enum e_item_style_type { + IS_DEFAULT, + IS_VOICE_INVITED, + IS_VOICE_JOINED, + IS_VOICE_LEFT, + IS_ONLINE, + IS_OFFLINE, + } EItemStyle; + class ContextMenu { public: @@ -73,7 +82,7 @@ public: void setOnline(bool online); void setName(const std::string& name); void setHighlight(const std::string& highlight); - void setStyle(const LLStyle::Params& new_style); + void setStyle(EItemStyle item_style); void setAvatarId(const LLUUID& id, bool ignore_status_changes = false); void setLastInteractionTime(U32 secs_since); //Show/hide profile/info btn, translating speaker indicator and avatar name coordinates accordingly @@ -105,6 +114,8 @@ protected: */ LLOutputMonitorCtrl* mSpeakingIndicator; + LLAvatarIconCtrl* mAvatarIcon; + private: typedef enum e_online_status { @@ -118,7 +129,12 @@ private: std::string formatSeconds(U32 secs); - LLAvatarIconCtrl* mAvatarIcon; + typedef std::map<EItemStyle, LLStyle::Params> item_style_map_t; + static item_style_map_t& getItemStylesParams(); + + typedef std::map<EItemStyle, LLColor4> icon_color_map_t; + static icon_color_map_t& getItemIconColorMap(); + LLTextBox* mAvatarName; LLTextBox* mLastInteractionTime; LLStyle::Params mAvatarNameStyle; diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 4d5d416907..976b312509 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -148,6 +148,12 @@ void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& nam { if (!getChicletPanel()) return; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (!session) return; + + // no need to spawn chiclets for participants in P2P calls called through Avaline + if (session->isP2P() && session->isOtherParticipantAvaline()) return; + if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return; LLIMChiclet* chiclet = createIMChiclet(session_id); diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index fe4f0c5525..1b4c274bfb 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -40,6 +40,7 @@ #include "llagent.h" #include "llagentdata.h" // for gAgentID +#include "llavatariconctrl.h" #include "llavatarlist.h" #include "llbottomtray.h" #include "llimfloater.h" @@ -48,6 +49,7 @@ #include "llspeakers.h" #include "lltransientfloatermgr.h" +static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids); class LLNonAvatarCaller : public LLAvatarListItem { @@ -66,6 +68,8 @@ public: showLastInteractionTime(false); setShowProfileBtn(false); setShowInfoBtn(false); + mAvatarIcon->setValue("Avaline_Icon"); + mAvatarIcon->setToolTip(std::string("")); } return rv; } @@ -79,10 +83,26 @@ static void* create_non_avatar_caller(void*) return new LLNonAvatarCaller; } +LLCallFloater::LLAvatarListItemRemoveTimer::LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id) +: LLEventTimer(period) +, mRemoveCallback(remove_cb) +, mSpeakerId(speaker_id) +{ +} + +BOOL LLCallFloater::LLAvatarListItemRemoveTimer::tick() +{ + if (mRemoveCallback) + { + mRemoveCallback(mSpeakerId); + } + return TRUE; +} + LLCallFloater::LLCallFloater(const LLSD& key) : LLDockableFloater(NULL, false, key) , mSpeakerManager(NULL) -, mPaticipants(NULL) +, mParticipants(NULL) , mAvatarList(NULL) , mNonAvatarCaller(NULL) , mVoiceType(VC_LOCAL_CHAT) @@ -90,7 +110,11 @@ LLCallFloater::LLCallFloater(const LLSD& key) , mSpeakingIndicator(NULL) , mIsModeratorMutedVoice(false) , mInitParticipantsVoiceState(false) +, mVoiceLeftRemoveDelay(10) { + static LLUICachedControl<S32> voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10); + mVoiceLeftRemoveDelay = voice_left_remove_delay; + mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL); LLVoiceClient::getInstance()->addObserver(this); LLTransientFloaterMgr::getInstance()->addControlView(this); @@ -98,8 +122,10 @@ LLCallFloater::LLCallFloater(const LLSD& key) LLCallFloater::~LLCallFloater() { - delete mPaticipants; - mPaticipants = NULL; + resetVoiceRemoveTimers(); + + delete mParticipants; + mParticipants = NULL; mAvatarListRefreshConnection.disconnect(); @@ -149,7 +175,11 @@ void LLCallFloater::draw() // It should be done only when she joins or leaves voice chat. // But seems that LLVoiceClientParticipantObserver is not enough to satisfy this requirement. // *TODO: mantipov: remove from draw() - onChange(); + + // NOTE: it looks like calling onChange() here is not necessary, + // but sometime it is not called properly from the observable object. + // Seems this is a problem somewhere in Voice Client (LLVoiceClient::participantAddedEvent) +// onChange(); bool is_moderator_muted = gVoiceClient->getIsModeratorMuted(gAgentID); @@ -159,8 +189,8 @@ void LLCallFloater::draw() } // Need to resort the participant list if it's in sort by recent speaker order. - if (mPaticipants) - mPaticipants->updateRecentSpeakersOrder(); + if (mParticipants) + mParticipants->updateRecentSpeakersOrder(); LLDockableFloater::draw(); } @@ -168,9 +198,17 @@ void LLCallFloater::draw() // virtual void LLCallFloater::onChange() { - if (NULL == mPaticipants) return; + if (NULL == mParticipants) return; updateParticipantsVoiceState(); + + // Add newly joined participants. + std::vector<LLUUID> speakers_uuids; + get_voice_participants_uuids(speakers_uuids); + for (std::vector<LLUUID>::const_iterator it = speakers_uuids.begin(); it != speakers_uuids.end(); it++) + { + mParticipants->addAvatarIDExceptAgent(*it); + } } @@ -251,7 +289,7 @@ void LLCallFloater::updateSession() bool is_local_chat = mVoiceType == VC_LOCAL_CHAT; childSetVisible("leave_call_btn", !is_local_chat); - refreshPartisipantList(); + refreshParticipantList(); updateAgentModeratorState(); //show floater for voice calls @@ -266,10 +304,17 @@ void LLCallFloater::updateSession() } } -void LLCallFloater::refreshPartisipantList() +void LLCallFloater::refreshParticipantList() { - delete mPaticipants; - mPaticipants = NULL; + // lets forget states from the previous session + // for timers... + resetVoiceRemoveTimers(); + + // ...and for speaker state + mSpeakerStateMap.clear(); + + delete mParticipants; + mParticipants = NULL; mAvatarList->clear(); bool non_avatar_caller = false; @@ -289,7 +334,8 @@ void LLCallFloater::refreshPartisipantList() if (!non_avatar_caller) { - mPaticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT); + mParticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT); + mParticipants->setValidateSpeakerCallback(boost::bind(&LLCallFloater::validateSpeaker, this, _1)); if (LLLocalSpeakerMgr::getInstance() == mSpeakerManager) { @@ -414,7 +460,7 @@ void LLCallFloater::updateAgentModeratorState() mAgentPanel->childSetValue("user_text", name); } -void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids) +static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids) { // Get a list of participants from VoiceClient LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList(); @@ -482,28 +528,10 @@ void LLCallFloater::updateParticipantsVoiceState() std::vector<LLUUID> speakers_list; // Get a list of participants from VoiceClient - LLVoiceClient::participantMap *map = gVoiceClient->getParticipantList(); - if (!map) return; - - for (LLVoiceClient::participantMap::const_iterator iter = map->begin(); - iter != map->end(); ++iter) - { - LLUUID id = (*iter).second->mAvatarID; -// if ( id != gAgent.getID() ) - { - speakers_list.push_back(id); -/* - LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*> (mAvatarList->getItemByValue(id)); - if (item) - { - setState(item, STATE_JOINED); - } -*/ - - } - } + std::vector<LLUUID> speakers_uuids; + get_voice_participants_uuids(speakers_uuids); - // Updating the status for each participant. + // Updating the status for each participant already in list. std::vector<LLPanel*> items; mAvatarList->getItems(items); std::vector<LLPanel*>::const_iterator @@ -518,14 +546,14 @@ void LLCallFloater::updateParticipantsVoiceState() const LLUUID participant_id = item->getAvatarId(); bool found = false; - std::vector<LLUUID>::iterator speakers_iter = std::find(speakers_list.begin(), speakers_list.end(), participant_id); + std::vector<LLUUID>::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id); lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl; // If an avatarID assigned to a panel is found in a speakers list // obtained from VoiceClient we assign the JOINED status to the owner // of this avatarID. - if (speakers_iter != speakers_list.end()) + if (speakers_iter != speakers_uuids.end()) { setState(item, STATE_JOINED); @@ -534,92 +562,163 @@ void LLCallFloater::updateParticipantsVoiceState() continue; speaker->mHasLeftCurrentCall = FALSE; - speakers_list.erase(speakers_iter); + speakers_uuids.erase(speakers_iter); found = true; } - // If an avatarID is not found in a speakers list from VoiceClient and - // a panel with this ID has a JOINED status this means that this person - // HAS LEFT the call. if (!found) { + // If an avatarID is not found in a speakers list from VoiceClient and + // a panel with this ID has a JOINED status this means that this person + // HAS LEFT the call. if ((getState(participant_id) == STATE_JOINED)) { - setState(item, STATE_LEFT); + if (mVoiceType == VC_LOCAL_CHAT) + { + // Don't display avatars that aren't in our nearby chat range anymore as "left". Remove them immediately. + removeVoiceLeftParticipant(participant_id); + } + else + { + setState(item, STATE_LEFT); - LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId()); - if (speaker.isNull()) - continue; + LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId()); + if (speaker.isNull()) + { + continue; + } - speaker->mHasLeftCurrentCall = TRUE; + speaker->mHasLeftCurrentCall = TRUE; + } } + // If an avatarID is not found in a speakers list from VoiceClient and + // a panel with this ID has a LEFT status this means that this person + // HAS ENTERED session but it is not in voice chat yet. So, set INVITED status else if ((getState(participant_id) != STATE_LEFT)) { setState(item, STATE_INVITED); } - -/* - // If there is already a started timer for the current panel don't do anything. - bool no_timer_for_current_panel = true; - if (mTimersMap.size() > 0) - { - timers_map::iterator found_it = mTimersMap.find(participant_id); - if (found_it != mTimersMap.end()) - { - no_timer_for_current_panel = false; - } - } - - if (no_timer_for_current_panel) + else { - // Starting a timer to remove an avatar row panel after timeout - // *TODO Make the timeout period adjustable - mTimersMap.insert(timer_pair(participant_id, new LLAvatarRowRemoveTimer(this->getHandle(), 10, participant_id))); + llwarns << "Unsupported (" << getState(participant_id) << ") state: " << item->getAvatarName() << llendl; } -*/ } } - } void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state) { - setState(item->getAvatarId(), state); + // *HACK: mantipov: sometimes such situation is possible while switching to voice channel: +/* + - voice channel is switched to the one user is joining + - participant list is initialized with voice states: agent is in voice + - than such log messages were found (with agent UUID) + - LLVivoxProtocolParser::process_impl: parsing: <Response requestId="22" action="Session.MediaDisconnect.1"><ReturnCode>0</ReturnCode><Results><StatusCode>0</StatusCode><StatusString /></Results><InputXml><Request requestId="22" action="Session.MediaDisconnect.1"><SessionGroupHandle>9</SessionGroupHandle><SessionHandle>12</SessionHandle><Media>Audio</Media></Request></InputXml></Response> + - LLVoiceClient::sessionState::removeParticipant: participant "sip:x2pwNkMbpR_mK4rtB_awASA==@bhr.vivox.com" (da9c0d90-c6e9-47f9-8ae2-bb41fdac0048) removed. + - and than while updating participants voice states agent is marked as HAS LEFT + - next updating of LLVoiceClient state makes agent JOINED + So, lets skip HAS LEFT state for agent's avatar +*/ + if (STATE_LEFT == state && item->getAvatarId() == gAgentID) return; - LLStyle::Params speaker_style; - LLFontDescriptor new_desc(speaker_style.font()->getFontDesc()); + setState(item->getAvatarId(), state); switch (state) { case STATE_INVITED: -// status_str = "INVITED"; // *TODO: localize - new_desc.setStyle(LLFontGL::NORMAL); + item->setStyle(LLAvatarListItem::IS_VOICE_INVITED); break; case STATE_JOINED: -// status_str = "JOINED"; // *TODO: localize - new_desc.setStyle(LLFontGL::NORMAL); + removeVoiceRemoveTimer(item->getAvatarId()); + item->setStyle(LLAvatarListItem::IS_VOICE_JOINED); break; case STATE_LEFT: { - // status_str = "HAS LEFT CALL"; // *TODO: localize - new_desc.setStyle(LLFontGL::ITALIC); - + setVoiceRemoveTimer(item->getAvatarId()); + item->setStyle(LLAvatarListItem::IS_VOICE_LEFT); } break; default: llwarns << "Unrecognized avatar panel state (" << state << ")" << llendl; break; } +} + +void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id) +{ + + // If there is already a started timer for the current panel don't do anything. + bool no_timer_for_current_panel = true; + if (mVoiceLeftTimersMap.size() > 0) + { + timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); + if (found_it != mVoiceLeftTimersMap.end()) + { + no_timer_for_current_panel = false; + } + } + + if (no_timer_for_current_panel) + { + // Starting a timer to remove an avatar row panel after timeout + mVoiceLeftTimersMap.insert(timer_pair(voice_speaker_id, + new LLAvatarListItemRemoveTimer(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), mVoiceLeftRemoveDelay, voice_speaker_id))); + } +} + +void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id) +{ + if (mVoiceLeftTimersMap.size() > 0) + { + mVoiceLeftTimersMap.erase(mVoiceLeftTimersMap.find(voice_speaker_id)); + } - LLFontGL* new_font = LLFontGL::getFont(new_desc); - speaker_style.font = new_font; - item->setStyle(speaker_style); + LLAvatarList::uuid_vector_t& speaker_uuids = mAvatarList->getIDs(); + LLAvatarList::uuid_vector_t::iterator pos = std::find(speaker_uuids.begin(), speaker_uuids.end(), voice_speaker_id); + if(pos != speaker_uuids.end()) + { + speaker_uuids.erase(pos); + mAvatarList->setDirty(); + } +} -// if () + +void LLCallFloater::resetVoiceRemoveTimers() +{ + if (mVoiceLeftTimersMap.size() > 0) { - // found speaker is in voice, mark him as online - item->setOnline(STATE_JOINED == state); + for (timers_map::iterator iter = mVoiceLeftTimersMap.begin(); + iter != mVoiceLeftTimersMap.end(); ++iter) + { + delete iter->second; + } } + mVoiceLeftTimersMap.clear(); +} + +void LLCallFloater::removeVoiceRemoveTimer(const LLUUID& voice_speaker_id) +{ + // Remove the timer if it has been already started + if (mVoiceLeftTimersMap.size() > 0) + { + timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); + if (found_it != mVoiceLeftTimersMap.end()) + { + delete found_it->second; + mVoiceLeftTimersMap.erase(found_it); + } + } +} + +bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id) +{ + if (mVoiceType != VC_LOCAL_CHAT) + return true; + + // A nearby chat speaker is considered valid it it's known to LLVoiceClient (i.e. has enabled voice). + std::vector<LLUUID> speakers; + get_voice_participants_uuids(speakers); + return std::find(speakers.begin(), speakers.end(), speaker_id) != speakers.end(); } //EOF diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 21fba433c6..3df9e333c5 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -57,6 +57,9 @@ class LLSpeakerMgr; class LLCallFloater : public LLDockableFloater, LLVoiceClientParticipantObserver { public: + + LOG_CLASS(LLCallFloater); + LLCallFloater(const LLSD& key); ~LLCallFloater(); @@ -105,7 +108,14 @@ private: /** * Refreshes participant list according to current Voice Channel */ - void refreshPartisipantList(); + void refreshParticipantList(); + + /** + * Handles event on avatar list is refreshed after it was marked dirty. + * + * It sets initial participants voice states (once after the first refreshing) + * and updates voice states each time anybody is joined/left voice chat in session. + */ void onAvatarListRefreshed(); @@ -114,7 +124,21 @@ private: void setModeratorMutedVoice(bool moderator_muted); void updateAgentModeratorState(); + /** + * Sets initial participants voice states in avatar list (Invited, Joined, Has Left). + * + * @see refreshParticipantList() + * @see onAvatarListRefreshed() + * @see mInitParticipantsVoiceState + */ void initParticipantsVoiceState(); + + /** + * Updates participants voice states in avatar list (Invited, Joined, Has Left). + * + * @see onAvatarListRefreshed() + * @see onChanged() + */ void updateParticipantsVoiceState(); void setState(LLAvatarListItem* item, ESpeakerState state); @@ -130,10 +154,48 @@ private: return mSpeakerStateMap[speaker_id]; } + + /** + * Instantiates new LLAvatarListItemRemoveTimer and adds it into the map if it is not already created. + * + * @param voice_speaker_id LLUUID of Avatar List item to be removed from the list when timer expires. + */ + void setVoiceRemoveTimer(const LLUUID& voice_speaker_id); + + /** + * Removes specified by UUID Avatar List item. + * + * @param voice_speaker_id LLUUID of Avatar List item to be removed from the list. + */ + void removeVoiceLeftParticipant(const LLUUID& voice_speaker_id); + + /** + * Deletes all timers from the list to prevent started timers from ticking after destruction + * and after switching on another voice channel. + */ + void resetVoiceRemoveTimers(); + + /** + * Removes specified by UUID timer from the map. + * + * @param voice_speaker_id LLUUID of Avatar List item whose timer should be removed from the map. + */ + void removeVoiceRemoveTimer(const LLUUID& voice_speaker_id); + + /** + * Called by LLParticipantList before adding a speaker to the participant list. + * + * If false is returned, the speaker will not be added to the list. + * + * @param speaker_id Speaker to validate. + * @return true if this is a valid speaker, false otherwise. + */ + bool validateSpeaker(const LLUUID& speaker_id); + private: speaker_state_map_t mSpeakerStateMap; LLSpeakerMgr* mSpeakerManager; - LLParticipantList* mPaticipants; + LLParticipantList* mParticipants; LLAvatarList* mAvatarList; LLNonAvatarCaller* mNonAvatarCaller; EVoiceControls mVoiceType; @@ -141,10 +203,45 @@ private: LLOutputMonitorCtrl* mSpeakingIndicator; bool mIsModeratorMutedVoice; + /** + * Flag indicated that participants voice states should be initialized. + * + * It is used due to Avatar List has delayed refreshing after it content is changed. + * Real initializing is performed when Avatar List is first time refreshed. + * + * @see onAvatarListRefreshed() + * @see initParticipantsVoiceState() + */ bool mInitParticipantsVoiceState; boost::signals2::connection mAvatarListRefreshConnection; + /** + * class LLAvatarListItemRemoveTimer + * + * Implements a timer that removes avatar list item of a participant + * who has left the call. + */ + class LLAvatarListItemRemoveTimer : public LLEventTimer + { + public: + typedef boost::function<void(const LLUUID&)> callback_t; + + LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id); + virtual ~LLAvatarListItemRemoveTimer() {}; + + virtual BOOL tick(); + + private: + callback_t mRemoveCallback; + LLUUID mSpeakerId; + }; + + typedef std::pair<LLUUID, LLAvatarListItemRemoveTimer*> timer_pair; + typedef std::map<LLUUID, LLAvatarListItemRemoveTimer*> timers_map; + + timers_map mVoiceLeftTimersMap; + S32 mVoiceLeftRemoveDelay; }; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 17ef1f41a4..c01202bb82 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -64,18 +64,6 @@ static LLDefaultChildRegistry::Register<LLAdHocChiclet> t5("chiclet_im_adhoc"); static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script"); static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer"); -static const LLRect CHICLET_RECT(0, 25, 25, 0); -static const LLRect CHICLET_ICON_RECT(0, 22, 22, 0); -static const LLRect VOICE_INDICATOR_RECT(50, 25, 70, 0); -static const LLRect COUNTER_RECT(25, 25, 50, 0); -static const S32 OVERLAY_ICON_SHIFT = 2; // used for shifting of an overlay icon for new massages in a chiclet -static const S32 SCROLL_BUTTON_PAD = 5; - -// static -const S32 LLChicletPanel::s_scroll_ratio = 10; -const S32 LLChicletNotificationCounterCtrl::MAX_DISPLAYED_COUNT = 99; - - boost::signals2::signal<LLChiclet* (const LLUUID&), LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > > LLIMChiclet::sFindChicletsSignal; @@ -173,6 +161,9 @@ LLSysWellChiclet::~LLSysWellChiclet() void LLSysWellChiclet::setCounter(S32 counter) { + // do nothing if the same counter is coming. EXT-3678. + if (counter == mCounter) return; + // note same code in LLChicletNotificationCounterCtrl::setCounter(S32 counter) std::string s_count; if(counter != 0) @@ -388,9 +379,9 @@ void LLNotificationChiclet::createMenu() ////////////////////////////////////////////////////////////////////////// LLChiclet::Params::Params() - : show_counter("show_counter") + : show_counter("show_counter", true) + , enable_counter("enable_counter", false) { - show_counter = true; } LLChiclet::LLChiclet(const Params& p) @@ -448,26 +439,12 @@ void LLChiclet::setValue(const LLSD& value) LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p) : LLChiclet(p) , mShowSpeaker(false) +, mDefaultWidth(p.rect().getWidth()) , mNewMessagesIcon(NULL) , mSpeakerCtrl(NULL) , mCounterCtrl(NULL) { - // initialize an overlay icon for new messages - LLIconCtrl::Params icon_params; - icon_params.visible = false; - icon_params.image = LLUI::getUIImage(p.new_messages_icon_name); - mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(icon_params); - addChild(mNewMessagesIcon); - - // adjust size and position of an icon - LLRect chiclet_rect = p.rect; - LLRect overlay_icon_rect = LLRect(chiclet_rect.getWidth()/2, chiclet_rect.getHeight(), chiclet_rect.getWidth(), chiclet_rect.getHeight()/2); - mNewMessagesIcon->setRect(overlay_icon_rect); - - // shift an icon a little bit to the right and up corner of a chiclet - overlay_icon_rect.translate(OVERLAY_ICON_SHIFT, OVERLAY_ICON_SHIFT); - - enableCounterControl(false); + enableCounterControl(p.enable_counter); } void LLIMChiclet::setShowSpeaker(bool show) @@ -477,7 +454,6 @@ void LLIMChiclet::setShowSpeaker(bool show) { mShowSpeaker = show; toggleSpeakerControl(); - onChicletSizeChanged(); } } @@ -502,7 +478,6 @@ void LLIMChiclet::setShowCounter(bool show) { LLChiclet::setShowCounter(show); toggleCounterControl(); - onChicletSizeChanged(); } } @@ -515,32 +490,37 @@ void LLIMChiclet::setRequiredWidth() { bool show_speaker = getShowSpeaker(); bool show_counter = getShowCounter(); - S32 required_width = CHICLET_RECT.getWidth(); + S32 required_width = mDefaultWidth; if (show_counter) { - required_width += COUNTER_RECT.getWidth(); + required_width += mCounterCtrl->getRect().getWidth(); } if (show_speaker) { - required_width += VOICE_INDICATOR_RECT.getWidth(); + required_width += mSpeakerCtrl->getRect().getWidth(); } reshape(required_width, getRect().getHeight()); + + onChicletSizeChanged(); } void LLIMChiclet::toggleSpeakerControl() { if(getShowSpeaker()) { + // move speaker to the right of chiclet icon + LLRect speaker_rc = mSpeakerCtrl->getRect(); + speaker_rc.setLeftTopAndSize(mDefaultWidth, speaker_rc.mTop, speaker_rc.getWidth(), speaker_rc.getHeight()); + mSpeakerCtrl->setRect(speaker_rc); + if(getShowCounter()) { - mSpeakerCtrl->setRect(VOICE_INDICATOR_RECT); - } - else - { - mSpeakerCtrl->setRect(COUNTER_RECT); + // move speaker to the right of counter + mSpeakerCtrl->translate(mCounterCtrl->getRect().getWidth(), 0); } + initSpeakerControl(); } @@ -567,6 +547,7 @@ void LLIMChiclet::setShowNewMessagesIcon(bool show) { mNewMessagesIcon->setVisible(show); } + setRequiredWidth(); } bool LLIMChiclet::getShowNewMessagesIcon() @@ -640,36 +621,9 @@ LLIMP2PChiclet::Params::Params() : avatar_icon("avatar_icon") , unread_notifications("unread_notifications") , speaker("speaker") +, new_message_icon("new_message_icon") , show_speaker("show_speaker") { - // *TODO Vadim: Get rid of hardcoded values. - rect(CHICLET_RECT); - - avatar_icon.name("avatar_icon"); - avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - - // *NOTE dzaporozhan - // Changed icon height from 25 to 24 to fix ticket EXT-794. - // In some cases(after changing UI scale) 25 pixel height icon was - // drawn incorrectly, i'm not sure why. - avatar_icon.rect(CHICLET_ICON_RECT); - avatar_icon.mouse_opaque(false); - - unread_notifications.name("unread"); - unread_notifications.font(LLFontGL::getFontSansSerif()); - unread_notifications.font_halign(LLFontGL::HCENTER); - unread_notifications.v_pad(5); - unread_notifications.text_color(LLColor4::white); - unread_notifications.mouse_opaque(false); - unread_notifications.rect(COUNTER_RECT); - unread_notifications.visible(false); - - speaker.name("speaker"); - speaker.rect(VOICE_INDICATOR_RECT); - speaker.auto_update(true); - speaker.draw_border(false); - - show_speaker = false; } LLIMP2PChiclet::LLIMP2PChiclet(const Params& p) @@ -677,6 +631,10 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p) , mChicletIconCtrl(NULL) , mPopupMenu(NULL) { + LLIconCtrl::Params new_msg_params = p.new_message_icon; + mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params); + addChild(mNewMessagesIcon); + LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon; mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params); addChild(mChicletIconCtrl); @@ -694,10 +652,6 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p) sendChildToFront(mNewMessagesIcon); setShowSpeaker(p.show_speaker); - - //since mShowSpeaker initialized with false - //setShowSpeaker(false) will not hide mSpeakerCtrl - mSpeakerCtrl->setVisible(getShowSpeaker()); } void LLIMP2PChiclet::initSpeakerControl() @@ -718,8 +672,11 @@ void LLIMP2PChiclet::updateMenuItems() if(getSessionId().isNull()) return; + LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId()); + bool open_window_exists = open_im_floater && open_im_floater->getVisible(); + mPopupMenu->getChild<LLUICtrl>("Send IM")->setEnabled(!open_window_exists); + bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId()); - mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend); } @@ -790,38 +747,10 @@ LLAdHocChiclet::Params::Params() : avatar_icon("avatar_icon") , unread_notifications("unread_notifications") , speaker("speaker") +, new_message_icon("new_message_icon") , show_speaker("show_speaker") , avatar_icon_color("avatar_icon_color", LLColor4::green) { - // *TODO Vadim: Get rid of hardcoded values. - rect(CHICLET_RECT); - - avatar_icon.name("avatar_icon"); - avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - - // *NOTE dzaporozhan - // Changed icon height from 25 to 24 to fix ticket EXT-794. - // In some cases(after changing UI scale) 25 pixel height icon was - // drawn incorrectly, i'm not sure why. - avatar_icon.rect(CHICLET_ICON_RECT); - avatar_icon.mouse_opaque(false); - - unread_notifications.name("unread"); - unread_notifications.font(LLFontGL::getFontSansSerif()); - unread_notifications.font_halign(LLFontGL::HCENTER); - unread_notifications.v_pad(5); - unread_notifications.text_color(LLColor4::white); - unread_notifications.mouse_opaque(false); - unread_notifications.rect(COUNTER_RECT); - unread_notifications.visible(false); - - - speaker.name("speaker"); - speaker.rect(VOICE_INDICATOR_RECT); - speaker.auto_update(true); - speaker.draw_border(false); - - show_speaker = false; } LLAdHocChiclet::LLAdHocChiclet(const Params& p) @@ -829,6 +758,10 @@ LLAdHocChiclet::LLAdHocChiclet(const Params& p) , mChicletIconCtrl(NULL) , mPopupMenu(NULL) { + LLIconCtrl::Params new_msg_params = p.new_message_icon; + mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params); + addChild(mNewMessagesIcon); + LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon; mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params); //Make the avatar modified @@ -941,32 +874,9 @@ LLIMGroupChiclet::Params::Params() : group_icon("group_icon") , unread_notifications("unread_notifications") , speaker("speaker") +, new_message_icon("new_message_icon") , show_speaker("show_speaker") { - rect(CHICLET_RECT); - - group_icon.name("group_icon"); - - // *NOTE dzaporozhan - // Changed icon height from 25 to 24 to fix ticket EXT-794. - // In some cases(after changing UI scale) 25 pixel height icon was - // drawn incorrectly, i'm not sure why. - group_icon.rect(CHICLET_ICON_RECT); - - unread_notifications.name("unread"); - unread_notifications.font(LLFontGL::getFontSansSerif()); - unread_notifications.font_halign(LLFontGL::HCENTER); - unread_notifications.v_pad(5); - unread_notifications.text_color(LLColor4::white); - unread_notifications.rect(COUNTER_RECT); - unread_notifications.visible(false); - - speaker.name("speaker"); - speaker.rect(VOICE_INDICATOR_RECT); - speaker.auto_update(true); - speaker.draw_border(false); - - show_speaker = false; } LLIMGroupChiclet::LLIMGroupChiclet(const Params& p) @@ -975,6 +885,10 @@ LLIMGroupChiclet::LLIMGroupChiclet(const Params& p) , mChicletIconCtrl(NULL) , mPopupMenu(NULL) { + LLIconCtrl::Params new_msg_params = p.new_message_icon; + mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params); + addChild(mNewMessagesIcon); + LLChicletGroupIconCtrl::Params avatar_params = p.group_icon; mChicletIconCtrl = LLUICtrlFactory::create<LLChicletGroupIconCtrl>(avatar_params); addChild(mChicletIconCtrl); @@ -1063,6 +977,18 @@ void LLIMGroupChiclet::changed(LLGroupChange gc) } } +void LLIMGroupChiclet::updateMenuItems() +{ + if(!mPopupMenu) + return; + if(getSessionId().isNull()) + return; + + LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId()); + bool open_window_exists = open_im_floater && open_im_floater->getVisible(); + mPopupMenu->getChild<LLUICtrl>("Chat")->setEnabled(!open_window_exists); +} + BOOL LLIMGroupChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) { if(!mPopupMenu) @@ -1072,6 +998,7 @@ BOOL LLIMGroupChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) if (mPopupMenu) { + updateMenuItems(); mPopupMenu->arrangeAndClear(); LLMenuGL::showPopup(this, mPopupMenu, x, y); } @@ -1125,16 +1052,10 @@ void LLIMGroupChiclet::onMenuItemClicked(const LLSD& user_data) LLChicletPanel::Params::Params() : chiclet_padding("chiclet_padding") , scrolling_offset("scrolling_offset") +, scroll_button_hpad("scroll_button_hpad") +, scroll_ratio("scroll_ratio") , min_width("min_width") { - chiclet_padding = 3; - scrolling_offset = 40; - - if (!min_width.isProvided()) - { - // min_width = 4 chiclets + 3 paddings - min_width = 180 + 3*chiclet_padding; - } }; LLChicletPanel::LLChicletPanel(const Params&p) @@ -1144,6 +1065,8 @@ LLChicletPanel::LLChicletPanel(const Params&p) , mRightScrollButton(NULL) , mChicletPadding(p.chiclet_padding) , mScrollingOffset(p.scrolling_offset) +, mScrollButtonHPad(p.scroll_button_hpad) +, mScrollRatio(p.scroll_ratio) , mMinWidth(p.min_width) , mShowControls(true) { @@ -1445,8 +1368,8 @@ void LLChicletPanel::reshape(S32 width, S32 height, BOOL called_from_parent ) bool need_show_scroll = needShowScroll(); if(need_show_scroll) { - mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD, - height, width - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0)); + mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad, + height, width - scroll_button_rect.getWidth() - mScrollButtonHPad, 0)); } else { @@ -1462,6 +1385,20 @@ void LLChicletPanel::reshape(S32 width, S32 height, BOOL called_from_parent ) } +S32 LLChicletPanel::notifyParent(const LLSD& info) +{ + if(info.has("notification")) + { + std::string str_notification = info["notification"]; + if(str_notification == "size_changes") + { + arrange(); + return 1; + } + } + return LLPanel::notifyParent(info); +} + void LLChicletPanel::arrange() { if(mChicletList.empty()) @@ -1490,8 +1427,8 @@ void LLChicletPanel::arrange() bool need_show_scroll = needShowScroll(); if(need_show_scroll) { - mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD, - rect.getHeight(), rect.getWidth() - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0)); + mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad, + rect.getHeight(), rect.getWidth() - scroll_button_rect.getWidth() - mScrollButtonHPad, 0)); } else { @@ -1655,7 +1592,7 @@ void LLChicletPanel::onRightScrollClick() void LLChicletPanel::onLeftScrollHeldDown() { S32 offset = mScrollingOffset; - mScrollingOffset = mScrollingOffset / s_scroll_ratio; + mScrollingOffset = mScrollingOffset / mScrollRatio; scrollLeft(); mScrollingOffset = offset; } @@ -1663,7 +1600,7 @@ void LLChicletPanel::onLeftScrollHeldDown() void LLChicletPanel::onRightScrollHeldDown() { S32 offset = mScrollingOffset; - mScrollingOffset = mScrollingOffset / s_scroll_ratio; + mScrollingOffset = mScrollingOffset / mScrollRatio; scrollRight(); mScrollingOffset = offset; } @@ -1725,7 +1662,7 @@ S32 LLChicletPanel::getTotalUnreadIMCount() ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// LLChicletNotificationCounterCtrl::Params::Params() -: max_displayed_count("max_displayed_count", MAX_DISPLAYED_COUNT) +: max_displayed_count("max_displayed_count", 99) { } @@ -1802,6 +1739,7 @@ LLChicletGroupIconCtrl::LLChicletGroupIconCtrl(const Params& p) : LLIconCtrl(p) , mDefaultIcon(p.default_icon) { + setValue(LLUUID::null); } void LLChicletGroupIconCtrl::setValue(const LLSD& value ) @@ -1853,20 +1791,23 @@ LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p) LLScriptChiclet::Params::Params() : icon("icon") + , new_message_icon("new_message_icon") { - // *TODO Vadim: Get rid of hardcoded values. - rect(CHICLET_RECT); - icon.rect(CHICLET_ICON_RECT); } LLScriptChiclet::LLScriptChiclet(const Params&p) : LLIMChiclet(p) , mChicletIconCtrl(NULL) { + LLIconCtrl::Params new_msg_params = p.new_message_icon; + mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params); + addChild(mNewMessagesIcon); + LLIconCtrl::Params icon_params = p.icon; mChicletIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params); - // Let "new message" icon be on top, else it will be hidden behind chiclet icon. - addChildInBack(mChicletIconCtrl); + addChild(mChicletIconCtrl); + + sendChildToFront(mNewMessagesIcon); } void LLScriptChiclet::setSessionId(const LLUUID& session_id) @@ -1905,20 +1846,24 @@ BOOL LLScriptChiclet::handleMouseDown(S32 x, S32 y, MASK mask) static const std::string INVENTORY_USER_OFFER ("UserGiveItem"); LLInvOfferChiclet::Params::Params() + : icon("icon") + , new_message_icon("new_message_icon") { - // *TODO Vadim: Get rid of hardcoded values. - rect(CHICLET_RECT); - icon.rect(CHICLET_ICON_RECT); } LLInvOfferChiclet::LLInvOfferChiclet(const Params&p) : LLIMChiclet(p) , mChicletIconCtrl(NULL) { + LLIconCtrl::Params new_msg_params = p.new_message_icon; + mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params); + addChild(mNewMessagesIcon); + LLChicletInvOfferIconCtrl::Params icon_params = p.icon; mChicletIconCtrl = LLUICtrlFactory::create<LLChicletInvOfferIconCtrl>(icon_params); - // Let "new message" icon be on top, else it will be hidden behind chiclet icon. - addChildInBack(mChicletIconCtrl); + addChild(mChicletIconCtrl); + + sendChildToFront(mNewMessagesIcon); } void LLInvOfferChiclet::setSessionId(const LLUUID& session_id) diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 2ab6abfb5b..ee9db10525 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -52,8 +52,6 @@ class LLChicletNotificationCounterCtrl : public LLTextBox { public: - static const S32 MAX_DISPLAYED_COUNT; - struct Params : public LLInitParam::Block<Params, LLTextBox::Params> { /** @@ -217,7 +215,8 @@ public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<bool> show_counter; + Optional<bool> show_counter, + enable_counter; Params(); }; @@ -323,10 +322,7 @@ public: }; struct Params : public LLInitParam::Block<Params, LLChiclet::Params> { - Optional<std::string> new_messages_icon_name; - - Params() : new_messages_icon_name("new_messages_icon_name", "Unread_IM") - {} + Params(){} }; @@ -437,6 +433,8 @@ protected: bool mShowSpeaker; bool mCounterEnabled; + /* initial width of chiclet, should not include counter or speaker width */ + S32 mDefaultWidth; LLIconCtrl* mNewMessagesIcon; LLChicletNotificationCounterCtrl* mCounterCtrl; @@ -482,6 +480,8 @@ public: Optional<LLChicletSpeakerCtrl::Params> speaker; + Optional<LLIconCtrl::Params> new_message_icon; + Optional<bool> show_speaker; Params(); @@ -521,6 +521,7 @@ protected: /** * Enables/disables menus based on relationship with other participant. + * Enables/disables "show session" menu item depending on visible IM floater existence. */ virtual void updateMenuItems(); @@ -544,6 +545,8 @@ public: Optional<LLChicletSpeakerCtrl::Params> speaker; + Optional<LLIconCtrl::Params> new_message_icon; + Optional<bool> show_speaker; Optional<LLColor4> avatar_icon_color; @@ -614,6 +617,8 @@ public: { Optional<LLIconCtrl::Params> icon; + Optional<LLIconCtrl::Params> new_message_icon; + Params(); }; @@ -654,6 +659,8 @@ public: { Optional<LLChicletInvOfferIconCtrl::Params> icon; + Optional<LLIconCtrl::Params> new_message_icon; + Params(); }; @@ -697,6 +704,8 @@ public: Optional<LLChicletSpeakerCtrl::Params> speaker; + Optional<LLIconCtrl::Params> new_message_icon; + Optional<bool> show_speaker; Params(); @@ -752,6 +761,11 @@ protected: virtual void onMenuItemClicked(const LLSD& user_data); /** + * Enables/disables "show session" menu item depending on visible IM floater existence. + */ + virtual void updateMenuItems(); + + /** * Displays popup menu. */ /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); @@ -931,7 +945,9 @@ public: struct Params : public LLInitParam::Block<Params, LLPanel::Params> { Optional<S32> chiclet_padding, - scrolling_offset; + scrolling_offset, + scroll_button_hpad, + scroll_ratio; Optional<S32> min_width; @@ -1021,6 +1037,8 @@ public: S32 getTotalUnreadIMCount(); + S32 notifyParent(const LLSD& info); + protected: LLChicletPanel(const Params&p); friend class LLUICtrlFactory; @@ -1148,6 +1166,8 @@ protected: S32 mChicletPadding; S32 mScrollingOffset; + S32 mScrollButtonHPad; + S32 mScrollRatio; S32 mMinWidth; bool mShowControls; static const S32 s_scroll_ratio; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 832626e007..ee33c189f9 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -162,9 +162,22 @@ public: if (!region_name.empty()) { LLToolTip::Params params; - params.message = llformat("%s\n%s (%d, %d, %d)", getLabelSelected().c_str(), region_name.c_str(), + std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ()); - params.sticky_rect = calcScreenRect(); + + params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str()); + + LLRect rect = calcScreenRect(); + LLFontGL* standart_font = LLFontGL::getFontSansSerif(); + if(standart_font) + { + S32 w = llmax((S32)(standart_font->getWidthF32(getLabelSelected())+0.5),(S32)(standart_font->getWidthF32(extra_message)+0.5)); + rect.mRight = rect.mLeft + w; + params.max_width = w; + } + + params.sticky_rect = rect; + LLToolTipMgr::instance().show(params); } return TRUE; @@ -984,7 +997,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) if (action == "open") { - teleport_via_landmark(item->getAssetUUID()); + onButtonClick(item->getUUID()); } else if (action == "about") { diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 9cca1b07db..474d2ca21f 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1822,6 +1822,13 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + // When there are no visible children drag and drop is handled + // by the folder which is the hierarchy root. + if (!handled && !hasVisibleChildren()) + { + handled = mFolders.front()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + } + if (handled) { lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderView" << llendl; diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 22658b4d65..7dd8ea694e 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -138,12 +138,7 @@ void LLGroupActions::startCall(const LLUUID& group_id) } // start the call - // *TODO: move this to LLIMMgr? - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); - if (session && session->mSessionInitialized) - gIMMgr->startCall(session_id); - else - gIMMgr->autoStartCallOnStartup(session_id); + gIMMgr->autoStartCallOnStartup(session_id); make_ui_sound("UISndStartIM"); } diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index acaa6076f8..259f629bdd 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -45,6 +45,7 @@ #include "llfloaterchat.h" #include "llfloaterreg.h" #include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container +#include "lllayoutstack.h" #include "lllineeditor.h" #include "lllogchat.h" #include "llpanelimcontrolpanel.h" @@ -56,6 +57,7 @@ #include "llvoicechannel.h" #include "lltransientfloatermgr.h" #include "llinventorymodel.h" +#include "llrootview.h" @@ -107,6 +109,7 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) default: break; } } + setOverlapsScreenChannel(true); } void LLIMFloater::onFocusLost() @@ -220,6 +223,12 @@ LLIMFloater::~LLIMFloater() //virtual BOOL LLIMFloater::postBuild() { + // User-resizable control panels in P2P sessions look ugly (EXT-3470). + if (mDialog == IM_NOTHING_SPECIAL || mDialog == IM_SESSION_P2P_INVITE) + { + getChild<LLLayoutStack>("im_panels")->setPanelUserResize("panel_im_control_panel", FALSE); + } + const LLUUID& other_party_id = LLIMModel::getInstance()->getOtherParticipantID(mSessionID); if (other_party_id.notNull()) { @@ -437,6 +446,16 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id) void LLIMFloater::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRectRaw(); + static S32 right_padding = 0; + if (right_padding == 0) + { + LLPanel* side_bar_tabs = + gViewerWindow->getRootView()->getChild<LLPanel> ( + "side_bar_tabs"); + right_padding = side_bar_tabs->getRect().getWidth(); + LLTransientFloaterMgr::getInstance()->addControlView(side_bar_tabs); + } + rect.mRight -= right_padding; } void LLIMFloater::setDocked(bool docked, bool pop_on_undock) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 8917cc11e1..37ab144934 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -243,10 +243,13 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES std::string joined_call = LLTrans::getString("joined_call"); std::string other_avatar_name = ""; + std::string message; + switch(mSessionType) { case AVALINE_SESSION: - // *TODO: test avaline calls (EXT-2211) + // no text notifications + break; case P2P_SESSION: gCacheName->getFullName(mOtherParticipantID, other_avatar_name); @@ -255,10 +258,13 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES switch(new_state) { case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, started_call); + message = other_avatar_name + " " + started_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); + break; case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), joined_call); + message = you + " " + joined_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); default: break; } @@ -268,37 +274,27 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES switch(new_state) { case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), started_call); + message = you + " " + started_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); break; case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, joined_call); + message = other_avatar_name + " " + joined_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); default: break; } } - - // Update speakers list when connected - if (LLVoiceChannel::STATE_CONNECTED == new_state) - { - mSpeakers->update(true); - } - break; case GROUP_SESSION: case ADHOC_SESSION: - // *TODO: determine call starter's name "other_avatar_name" (EXT-2211) - // decide how to show notifications for a group/adhoc chat already opened - // for now there is no notification from voice channel for this case if(direction == LLVoiceChannel::INCOMING_CALL) { switch(new_state) { - case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, started_call); - break; case LLVoiceChannel::STATE_CONNECTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), joined_call); + message = you + " " + joined_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); default: break; } @@ -308,19 +304,18 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES switch(new_state) { case LLVoiceChannel::STATE_CALL_STARTED : - LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), started_call); + message = you + " " + started_call; + LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message); break; default: break; } } - - // Update speakers list when connected - if (LLVoiceChannel::STATE_CONNECTED == new_state) - { - mSpeakers->update(true); - } - break; + } + // Update speakers list when connected + if (LLVoiceChannel::STATE_CONNECTED == new_state) + { + mSpeakers->update(true); } } @@ -429,6 +424,61 @@ LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const (LLIMModel::LLIMSession*) NULL); } +//*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code +LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const std::vector<LLUUID>& ids) +{ + S32 num = ids.size(); + if (!num) return NULL; + + if (mId2SessionMap.empty()) return NULL; + + std::map<LLUUID, LLIMSession*>::const_iterator it = mId2SessionMap.begin(); + for (; it != mId2SessionMap.end(); ++it) + { + LLIMSession* session = (*it).second; + + if (!session->isAdHoc()) continue; + if (session->mInitialTargetIDs.size() != num) continue; + + std::list<LLUUID> tmp_list(session->mInitialTargetIDs.begin(), session->mInitialTargetIDs.end()); + + std::vector<LLUUID>::const_iterator iter = ids.begin(); + while (iter != ids.end()) + { + tmp_list.remove(*iter); + ++iter; + + if (tmp_list.empty()) + { + break; + } + } + + if (tmp_list.empty() && iter == ids.end()) + { + return session; + } + } + + return NULL; +} + +bool LLIMModel::LLIMSession::isAdHoc() +{ + return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID)); +} + +bool LLIMModel::LLIMSession::isP2P() +{ + return IM_NOTHING_SPECIAL == mType; +} + +bool LLIMModel::LLIMSession::isOtherParticipantAvaline() +{ + return !mOtherParticipantIsAvatar; +} + + void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) { LLIMSession* session = findIMSession(old_session_id); @@ -1403,11 +1453,20 @@ void LLCallDialog::getAllowedRect(LLRect& rect) rect = gViewerWindow->getWorldViewRectScaled(); } -void LLCallDialog::onOpen(const LLSD& key) +BOOL LLCallDialog::postBuild() { + if (!LLDockableFloater::postBuild()) + return FALSE; + // dock the dialog to the Speak Button, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), - this, getDockTongue(), LLDockControl::TOP, boost::bind(&LLCallDialog::getAllowedRect, this, _1))); + LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("speak_panel"); + + setDockControl(new LLDockControl( + anchor_panel, this, + getDockTongue(), LLDockControl::TOP, + boost::bind(&LLCallDialog::getAllowedRect, this, _1))); + + return TRUE; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1423,13 +1482,17 @@ LLCallDialog(payload) } } -void LLOutgoingCallDialog::draw() +void LLCallDialog::draw() { if (lifetimeHasExpired()) { onLifetimeExpired(); } - LLDockableFloater::draw(); + + if (getDockControl() != NULL) + { + LLDockableFloater::draw(); + } } bool LLOutgoingCallDialog::lifetimeHasExpired() @@ -1437,7 +1500,7 @@ bool LLOutgoingCallDialog::lifetimeHasExpired() if (mLifetimeTimer.getStarted()) { F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); - if (elapsed_time > LIFETIME) + if (elapsed_time > mLifetime) { return true; } @@ -1458,6 +1521,13 @@ void LLOutgoingCallDialog::show(const LLSD& key) // hide all text at first hideAllText(); + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + // customize text strings // tell the user which voice channel they are leaving if (!mPayload["old_channel_name"].asString().empty()) @@ -1551,7 +1621,7 @@ void LLOutgoingCallDialog::onCancel(void* user_data) BOOL LLOutgoingCallDialog::postBuild() { - BOOL success = LLDockableFloater::postBuild(); + BOOL success = LLCallDialog::postBuild(); childSetAction("Cancel", onCancel, this); @@ -1568,14 +1638,50 @@ LLCallDialog(payload) { } +bool LLIncomingCallDialog::lifetimeHasExpired() +{ + if (mLifetimeTimer.getStarted()) + { + F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); + if (elapsed_time > mLifetime) + { + return true; + } + } + return false; +} + +void LLIncomingCallDialog::onLifetimeExpired() +{ + // check whether a call is valid or not + if (LLVoiceClient::getInstance()->findSession(mPayload["caller_id"].asUUID())) + { + // restart notification's timer if call is still valid + mLifetimeTimer.start(); + } + else + { + // close invitation if call is already not valid + mLifetimeTimer.stop(); + closeFloater(); + } +} + BOOL LLIncomingCallDialog::postBuild() { - LLDockableFloater::postBuild(); + LLCallDialog::postBuild(); LLUUID session_id = mPayload["session_id"].asUUID(); LLSD caller_id = mPayload["caller_id"]; std::string caller_name = mPayload["caller_name"].asString(); + // init notification's lifetime + std::istringstream ss( getString("lifetime") ); + if (!(ss >> mLifetime)) + { + mLifetime = DEFAULT_LIFETIME; + } + std::string call_type; if (gAgent.isInGroup(session_id)) { @@ -1606,13 +1712,30 @@ BOOL LLIncomingCallDialog::postBuild() LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); caller_name_widget->setValue(caller_name + " " + call_type); LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); - icon->setValue(caller_id); + if (is_avatar) + { + icon->setValue(caller_id); + } + else + { + icon->setValue("Avaline_Icon"); + } childSetAction("Accept", onAccept, this); childSetAction("Reject", onReject, this); childSetAction("Start IM", onStartIM, this); childSetFocus("Accept"); + if(mPayload["notify_box_type"] != "VoiceInviteGroup" && mPayload["notify_box_type"] != "VoiceInviteAdHoc") + { + // starting notification's timer for P2P and AVALINE invitations + mLifetimeTimer.start(); + } + else + { + mLifetimeTimer.stop(); + } + return TRUE; } @@ -1743,6 +1866,14 @@ void LLIncomingCallDialog::processCallResponse(S32 response) new LLViewerChatterBoxInvitationAcceptResponder( session_id, inv_type)); + + // send notification message to the corresponding chat + if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc") + { + std::string started_call = LLTrans::getString("started_call"); + std::string message = mPayload["caller_name"].asString() + " " + started_call; + LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message); + } } } if (voice) @@ -2097,7 +2228,13 @@ BOOL LLIMMgr::getIMReceived() const void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id) { LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); - if (session) + if (!session) return; + + if (session->mSessionInitialized) + { + startCall(session_id); + } + else { session->mStartCallOnInitialize = true; } @@ -2159,12 +2296,22 @@ LLUUID LLIMMgr::addSession( bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); + //works only for outgoing ad-hoc sessions + if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) + { + LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids); + if (ad_hoc_found) + { + new_session = false; + session_id = ad_hoc_found->mSessionID; + } + } + if (new_session) { LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); } - //*TODO remove this "floater" thing when Communicate Floater's gone LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(!floater) @@ -2394,6 +2541,11 @@ void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body if (speaker_mgr) { speaker_mgr->updateSpeakers(body); + + // also the same call is added into LLVoiceClient::participantUpdatedEvent because + // sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post() + // when moderation state changed too late. See EXT-3544. + speaker_mgr->update(true); } else { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 09f0c9df71..cec9d1642f 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -74,6 +74,10 @@ public: void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction); static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); + bool isAdHoc(); + bool isP2P(); + bool isOtherParticipantAvaline(); + LLUUID mSessionID; std::string mName; EInstantMessage mType; @@ -133,6 +137,12 @@ public: */ LLIMSession* findIMSession(const LLUUID& session_id) const; + /** + * Find an Ad-Hoc IM Session with specified participants + * @return first found Ad-Hoc session or NULL if the session does not exist + */ + LLIMSession* findAdHocIMSession(const std::vector<LLUUID>& ids); + /** * Rebind session data to a new session id. */ @@ -476,9 +486,20 @@ public: LLCallDialog(const LLSD& payload); ~LLCallDialog() {} - virtual void onOpen(const LLSD& key); + virtual BOOL postBuild(); + + // check timer state + /*virtual*/ void draw(); protected: + // lifetime timer for a notification + LLTimer mLifetimeTimer; + // notification's lifetime in seconds + S32 mLifetime; + static const S32 DEFAULT_LIFETIME = 5; + virtual bool lifetimeHasExpired() {return false;}; + virtual void onLifetimeExpired() {}; + virtual void getAllowedRect(LLRect& rect); LLSD mPayload; }; @@ -496,6 +517,8 @@ public: static void onStartIM(void* user_data); private: + /*virtual*/ bool lifetimeHasExpired(); + /*virtual*/ void onLifetimeExpired(); void processCallResponse(S32 response); }; @@ -510,19 +533,11 @@ public: static void onCancel(void* user_data); static const LLUUID OCD_KEY; - // check timer state - /*virtual*/ void draw(); - private: - // hide all text boxes void hideAllText(); - // lifetime timer for NO_ANSWER notification - LLTimer mLifetimeTimer; - // lifetime duration for NO_ANSWER notification - static const S32 LIFETIME = 5; - bool lifetimeHasExpired(); - void onLifetimeExpired(); + /*virtual*/ bool lifetimeHasExpired(); + /*virtual*/ void onLifetimeExpired(); }; // Globals diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3fc2cbecbe..d70221b22a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4555,18 +4555,8 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod } else if (isRemoveAction(action)) { - if (get_is_item_worn(mUUID)) - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onRemoveFromAvatarArrived, - new OnRemoveStruct(mUUID)); - } - } + removeFromAvatar(); + return; } else LLItemBridge::performAction(folder, model, action); } @@ -4949,6 +4939,66 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, delete on_remove_struct; } +/* static */ +void LLWearableBridge::removeAllClothesFromAvatar() +{ + // Remove COF links. + for (S32 itype = WT_SHAPE; itype < WT_COUNT; ++itype) + { + if (itype == WT_SHAPE || itype == WT_SKIN || itype == WT_HAIR || itype == WT_EYES) + continue; + + // MULTI-WEARABLES: fixed to index 0 + LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>( + gAgentWearables.getWearableInventoryItem((EWearableType)itype, 0)); + if (!item) + continue; + const LLUUID &item_id = gInventory.getLinkedItemID(item->getUUID()); + const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id); + if (!wearable) + continue; + + // Find and remove this item from the COF. + LLInventoryModel::item_array_t items = gInventory.collectLinkedItems( + item_id, LLAppearanceManager::instance().getCOF()); + llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. + for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); + iter != items.end(); + ++iter) + { + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + gInventory.purgeObject(item_id); + } + } + gInventory.notifyObservers(); + + // Remove wearables from gAgentWearables + LLAgentWearables::userRemoveAllClothes(); +} + +/* static */ +void LLWearableBridge::removeItemFromAvatar(LLViewerInventoryItem *item) +{ + if (item) + { + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + LLWearableBridge::onRemoveFromAvatarArrived, + new OnRemoveStruct(item->getUUID())); + } +} + +void LLWearableBridge::removeFromAvatar() +{ + if (get_is_item_worn(mUUID)) + { + LLViewerInventoryItem* item = getItem(); + removeItemFromAvatar(item); + } +} + LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, const LLUUID& uuid,LLInventoryModel* model) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 4d83e9b684..cc1fa45b26 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -572,7 +572,10 @@ public: static BOOL canRemoveFromAvatar( void* userdata ); static void onRemoveFromAvatar( void* userdata ); - static void onRemoveFromAvatarArrived( LLWearable* wearable, void* userdata ); + static void onRemoveFromAvatarArrived( LLWearable* wearable, void* userdata ); + static void removeItemFromAvatar(LLViewerInventoryItem *item); + static void removeAllClothesFromAvatar(); + void removeFromAvatar(); protected: LLWearableBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLAssetType::EType asset_type, LLInventoryType::EType inv_type, EWearableType wearable_type) : diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 1eb8d1bc2c..711114173c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2654,6 +2654,33 @@ void LLInventoryModel::buildParentChildMap() cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); if(catsp) { + // *HACK - fix root inventory folder + // some accounts has pbroken inventory root folders + + std::string name = "My Inventory"; + LLUUID prev_root_id = mRootFolderID; + for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), + it_end = mParentChildCategoryTree.end(); it != it_end; ++it) + { + cat_array_t* cat_array = it->second; + for (cat_array_t::const_iterator cat_it = cat_array->begin(), + cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) + { + LLPointer<LLViewerInventoryCategory> category = *cat_it; + + if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) + continue; + if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) + { + if(category->getUUID()!=mRootFolderID) + { + LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID); + new_inv_root_folder_id = category->getUUID(); + } + } + } + } + // 'My Inventory', // root of the agent's inv found. // The inv tree is built. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 082b7a9468..164e72e621 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -628,9 +628,15 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* accept, std::string& tooltip_msg) { - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + // If folder view is empty the (x, y) point won't be in its rect + // so the handler must be called explicitly. + if (!mFolders->hasVisibleChildren()) + { + handled = mFolders->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + if (handled) { mFolders->setDragAndDropThisFrame(); diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 818e7e0db1..0ab3b07aea 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -684,7 +684,6 @@ void LLPanelStandStopFlying::onStopFlyingButtonClick() gAgent.setFlying(FALSE); setFocus(FALSE); // EXT-482 - setVisible(FALSE); } /** diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 1a0183a8ba..2ad82d3e8e 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -198,7 +198,7 @@ void LLNearbyChat::addMessage(const LLChat& chat,bool archive) } else { - mChatHistory->appendMessage(chat,use_plain_text_chat_history); + mChatHistory->appendMessage(chat, use_plain_text_chat_history); } } diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 169560f688..9e13a626b4 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -335,7 +335,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg) if (tmp_chat.mChatStyle == CHAT_STYLE_IRC) { if(!tmp_chat.mFromName.empty()) - tmp_chat.mText = tmp_chat.mFromName + " " + tmp_chat.mText.substr(3); + tmp_chat.mText = tmp_chat.mFromName + tmp_chat.mText.substr(3); else tmp_chat.mText = tmp_chat.mText.substr(3); } diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index c3df4cbaf4..52de8355e9 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -93,6 +93,19 @@ bool LLAlertHandler::processNotification(const LLSD& notify) if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "load") { + if (LLHandlerUtil::canSpawnSessionAndLogToIM(notification)) + { + const std::string name = LLHandlerUtil::getSubstitutionName(notification); + + LLUUID from_id = notification->getPayload()["from_id"]; + + // firstly create session... + LLHandlerUtil::spawnIMSession(name, from_id); + + // ...then log message to have IM Well notified about new message + LLHandlerUtil::logToIMP2P(notification); + } + LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); LLToast::Params p; p.notif_id = notification->getID(); diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 515c86bae8..0fb438bfe9 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -277,6 +277,13 @@ public: static bool canSpawnIMSession(const LLNotificationPtr& notification); /** + * Checks if passed notification can create IM session and be written into it. + * + * This method uses canLogToIM() & canSpawnIMSession(). + */ + static bool canSpawnSessionAndLogToIM(const LLNotificationPtr& notification); + + /** * Writes notification message to IM session. */ static void logToIM(const EInstantMessage& session_type, @@ -298,6 +305,20 @@ public: * Writes notification message to nearby chat. */ static void logToNearbyChat(const LLNotificationPtr& notification, EChatSourceType type); + + /** + * Spawns IM session. + */ + static void spawnIMSession(const std::string& name, const LLUUID& from_id); + + /** + * Returns name from the notification's substitution. + * + * Methods gets "NAME" or "[NAME]" from the substitution map. + * + * @param notification - Notification which substitution's name will be returned. + */ + static std::string getSubstitutionName(const LLNotificationPtr& notification); }; } diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 5b54092c5c..fba5773602 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -47,11 +47,15 @@ const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), "ObjectGiveItem"), OBJECT_GIVE_ITEM_UNKNOWN_USER( "ObjectGiveItemUnknownUser"), PAYMENT_RECIVED("PaymentRecived"), ADD_FRIEND_WITH_MESSAGE("AddFriendWithMessage"), - USER_GIVE_ITEM("UserGiveItem"), OFFER_FRIENDSHIP("OfferFriendship"), + USER_GIVE_ITEM("UserGiveItem"), + INVENTORY_ACCEPTED("InventoryAccepted"), + INVENTORY_DECLINED("InventoryDeclined"), + OFFER_FRIENDSHIP("OfferFriendship"), FRIENDSHIP_ACCEPTED("FriendshipAccepted"), FRIENDSHIP_OFFERED("FriendshipOffered"), FRIEND_ONLINE("FriendOnline"), FRIEND_OFFLINE("FriendOffline"), - SERVER_OBJECT_MESSAGE("ServerObjectMessage"); + SERVER_OBJECT_MESSAGE("ServerObjectMessage"), + TELEPORT_OFFERED("TeleportOffered"); // static bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) @@ -59,8 +63,11 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) return GRANTED_MODIFY_RIGHTS == notification->getName() || REVOKED_MODIFY_RIGHTS == notification->getName() || PAYMENT_RECIVED == notification->getName() + || OFFER_FRIENDSHIP == notification->getName() || FRIENDSHIP_OFFERED == notification->getName() - || SERVER_OBJECT_MESSAGE == notification->getName(); + || SERVER_OBJECT_MESSAGE == notification->getName() + || INVENTORY_ACCEPTED == notification->getName() + || INVENTORY_DECLINED == notification->getName(); } // static @@ -68,15 +75,25 @@ bool LLHandlerUtil::canLogToNearbyChat(const LLNotificationPtr& notification) { return notification->getType() == "notifytip" && FRIEND_ONLINE != notification->getName() - && FRIEND_OFFLINE != notification->getName(); + && FRIEND_OFFLINE != notification->getName() + && INVENTORY_ACCEPTED != notification->getName() + && INVENTORY_DECLINED != notification->getName(); } // static bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification) { - return ADD_FRIEND_WITH_MESSAGE == notification->getName() - || OFFER_FRIENDSHIP == notification->getName() - || FRIENDSHIP_ACCEPTED == notification->getName(); + return OFFER_FRIENDSHIP == notification->getName() + || FRIENDSHIP_ACCEPTED == notification->getName() + || USER_GIVE_ITEM == notification->getName() + || INVENTORY_ACCEPTED == notification->getName() + || INVENTORY_DECLINED == notification->getName(); +} + +// static +bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notification) +{ + return canLogToIM(notification) && canSpawnIMSession(notification); } // static @@ -113,10 +130,7 @@ void LLHandlerUtil::logToIM(const EInstantMessage& session_type, // static void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification) { - const std::string - name = - notification->getSubstitutions().has("NAME") ? notification->getSubstitutions()["NAME"] - : notification->getSubstitutions()["[NAME]"]; + const std::string name = LLHandlerUtil::getSubstitutionName(notification); const std::string session_name = notification->getPayload().has( "SESSION_NAME") ? notification->getPayload()["SESSION_NAME"].asString() : name; @@ -169,3 +183,23 @@ void LLHandlerUtil::logToNearbyChat(const LLNotificationPtr& notification, EChat } } +// static +void LLHandlerUtil::spawnIMSession(const std::string& name, const LLUUID& from_id) +{ + LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, from_id); + + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( + session_id); + if (session == NULL) + { + LLIMMgr::instance().addSession(name, IM_NOTHING_SPECIAL, from_id); + } +} + +// static +std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notification) +{ + return notification->getSubstitutions().has("NAME") + ? notification->getSubstitutions()["NAME"] + : notification->getSubstitutions()["[NAME]"]; +} diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 4d64c5c0e4..dd66a6c507 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -105,22 +105,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify) { if (LLHandlerUtil::canSpawnIMSession(notification)) { - const std::string name = notification->getSubstitutions().has( - "NAME") ? notification->getSubstitutions()["NAME"] - : notification->getSubstitutions()["[NAME]"]; + const std::string name = LLHandlerUtil::getSubstitutionName(notification); LLUUID from_id = notification->getPayload()["from_id"]; - LLUUID session_id = LLIMMgr::computeSessionID( - IM_NOTHING_SPECIAL, from_id); - - LLIMModel::LLIMSession* session = - LLIMModel::instance().findIMSession(session_id); - if (session == NULL) - { - LLIMMgr::instance().addSession(name, IM_NOTHING_SPECIAL, - from_id); - } + LLHandlerUtil::spawnIMSession(name, from_id); } if (notification->getPayload().has("SUPPRES_TOST") diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 9afaddae82..83a2215ac6 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -101,6 +101,19 @@ bool LLTipHandler::processNotification(const LLSD& notify) } } + const std::string name = notification->getSubstitutions()["NAME"]; + LLUUID from_id = notification->getPayload()["from_id"]; + if (LLHandlerUtil::canLogToIM(notification)) + { + LLHandlerUtil::logToIM(IM_NOTHING_SPECIAL, name, name, + notification->getMessage(), from_id, from_id); + } + + if (LLHandlerUtil::canSpawnIMSession(notification)) + { + LLHandlerUtil::spawnIMSession(name, from_id); + } + LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification); LLToast::Params p; diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index fa16cb6473..63803469dd 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -64,10 +64,6 @@ LLOutputMonitorCtrl::Params::Params() auto_update("auto_update"), speaker_id("speaker_id") { - draw_border = true; - name = "output_monitor"; - follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); - mouse_opaque = false; }; LLOutputMonitorCtrl::LLOutputMonitorCtrl(const LLOutputMonitorCtrl::Params& p) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index e9131a342e..913152e259 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -179,6 +179,10 @@ void LLPanelAvatarNotes::onOpen(const LLSD& key) void LLPanelAvatarNotes::fillRightsData() { + childSetValue("status_check", FALSE); + childSetValue("map_check", FALSE); + childSetValue("objects_check", FALSE); + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); // If true - we are viewing friend's profile, enable check boxes and set values. if(relation) diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 3f309b3bf5..a8a75a1feb 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -65,7 +65,11 @@ void LLPanelChatControlPanel::onOpenVoiceControlsClicked() void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) { - bool is_call_started = ( new_state >= LLVoiceChannel::STATE_CALL_STARTED ); + updateButtons(new_state >= LLVoiceChannel::STATE_CALL_STARTED); +} + +void LLPanelChatControlPanel::updateButtons(bool is_call_started) +{ childSetVisible("end_call_btn", is_call_started); childSetVisible("voice_ctrls_btn", is_call_started); childSetVisible("call_btn", ! is_call_started); @@ -112,6 +116,9 @@ void LLPanelChatControlPanel::setSessionId(const LLUUID& session_id) if(voice_channel) { mVoiceChannelStateChangeConnection = voice_channel->setStateChangedCallback(boost::bind(&LLPanelChatControlPanel::onVoiceChannelStateChanged, this, _1, _2)); + + //call (either p2p, group or ad-hoc) can be already in started state + updateButtons(voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); } } diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index 711340efc7..c18be5a6df 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -57,6 +57,8 @@ public: virtual void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state); + void updateButtons(bool is_call_started); + virtual void setSessionId(const LLUUID& session_id); const LLUUID& getSessionId() { return mSessionId; } diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 5de7c3f851..597b8bdb2d 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -81,7 +81,8 @@ BOOL LLPanelLandmarkInfo::postBuild() mCreator = getChild<LLTextBox>("creator"); mCreated = getChild<LLTextBox>("created"); - mTitleEditor = getChild<LLLineEditor>("title_editor"); + mLandmarkTitle = getChild<LLTextBox>("title_value"); + mLandmarkTitleEditor = getChild<LLLineEditor>("title_editor"); mNotesEditor = getChild<LLTextEditor>("notes_editor"); mFolderCombo = getChild<LLComboBox>("folder_combo"); @@ -101,7 +102,8 @@ void LLPanelLandmarkInfo::resetLocation() mCreator->setText(not_available); mOwner->setText(not_available); mCreated->setText(not_available); - mTitleEditor->setText(LLStringUtil::null); + mLandmarkTitle->setText(LLStringUtil::null); + mLandmarkTitleEditor->setText(LLStringUtil::null); mNotesEditor->setText(LLStringUtil::null); } @@ -122,7 +124,8 @@ void LLPanelLandmarkInfo::setInfoType(INFO_TYPE type) case CREATE_LANDMARK: mCurrentTitle = getString("title_create_landmark"); - mTitleEditor->setEnabled(TRUE); + mLandmarkTitle->setVisible(FALSE); + mLandmarkTitleEditor->setVisible(TRUE); mNotesEditor->setEnabled(TRUE); break; @@ -130,7 +133,8 @@ void LLPanelLandmarkInfo::setInfoType(INFO_TYPE type) default: mCurrentTitle = getString("title_landmark"); - mTitleEditor->setEnabled(FALSE); + mLandmarkTitle->setVisible(TRUE); + mLandmarkTitleEditor->setVisible(FALSE); mNotesEditor->setEnabled(FALSE); break; } @@ -185,12 +189,12 @@ void LLPanelLandmarkInfo::processParcelInfo(const LLParcelData& parcel_data) { if (parcel_data.name.empty()) { - mTitleEditor->setText(llformat("%s (%d, %d, %d)", + mLandmarkTitleEditor->setText(llformat("%s (%d, %d, %d)", parcel_data.sim_name.c_str(), region_x, region_y, region_z)); } else { - mTitleEditor->setText(parcel_data.name); + mLandmarkTitleEditor->setText(parcel_data.name); } std::string desc; @@ -281,7 +285,8 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem) mCreated->setText(timeStr); } - mTitleEditor->setText(pItem->getName()); + mLandmarkTitle->setText(pItem->getName()); + mLandmarkTitleEditor->setText(pItem->getName()); mNotesEditor->setText(pItem->getDescription()); } @@ -296,11 +301,14 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled) else { mTitle->setText(mCurrentTitle); + + mLandmarkTitle->setText(mLandmarkTitleEditor->getText()); } if (mNotesEditor->getReadOnly() == (enabled == TRUE)) { - mTitleEditor->setEnabled(enabled); + mLandmarkTitle->setVisible(!enabled); + mLandmarkTitleEditor->setVisible(enabled); mNotesEditor->setReadOnly(!enabled); mFolderCombo->setVisible(enabled); getChild<LLTextBox>("folder_label")->setVisible(enabled); @@ -313,7 +321,7 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled) const std::string& LLPanelLandmarkInfo::getLandmarkTitle() const { - return mTitleEditor->getText(); + return mLandmarkTitleEditor->getText(); } const std::string LLPanelLandmarkInfo::getLandmarkNotes() const @@ -333,7 +341,7 @@ BOOL LLPanelLandmarkInfo::setLandmarkFolder(const LLUUID& id) void LLPanelLandmarkInfo::createLandmark(const LLUUID& folder_id) { - std::string name = mTitleEditor->getText(); + std::string name = mLandmarkTitleEditor->getText(); std::string desc = mNotesEditor->getText(); LLStringUtil::trim(name); diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h index 73e0ddb9cc..2a9949ae41 100644 --- a/indra/newview/llpanellandmarkinfo.h +++ b/indra/newview/llpanellandmarkinfo.h @@ -77,7 +77,8 @@ private: LLTextBox* mOwner; LLTextBox* mCreator; LLTextBox* mCreated; - LLLineEditor* mTitleEditor; + LLTextBox* mLandmarkTitle; + LLLineEditor* mLandmarkTitleEditor; LLTextEditor* mNotesEditor; LLComboBox* mFolderCombo; }; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index e16bac2098..87abb16395 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -49,9 +49,9 @@ #include "llfloaterworldmap.h" #include "llfolderviewitem.h" #include "llinventorypanel.h" -#include "llinventorysubtreepanel.h" #include "lllandmarkactions.h" #include "llplacesinventorybridge.h" +#include "llplacesinventorypanel.h" #include "llsidetray.h" #include "llviewermenu.h" #include "llviewerregion.h" @@ -66,15 +66,54 @@ static const std::string TRASH_BUTTON_NAME = "trash_btn"; // helper functions -static void filter_list(LLInventorySubTreePanel* inventory_list, const std::string& string); -static void save_folder_state_if_no_filter(LLInventorySubTreePanel* inventory_list); +static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string); +static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list); /** - * Bridge to support knowing when the inventory has changed to update folder (open/close) state - * for landmarks panels. - * - * Due to Inventory data are loaded in background we need to save folder state each time - * next level is loaded. See EXT-3094. + * Functor counting expanded and collapsed folders in folder view tree to know + * when to enable or disable "Expand all folders" and "Collapse all folders" commands. + */ +class LLCheckFolderState : public LLFolderViewFunctor +{ +public: + LLCheckFolderState() + : mCollapsedFolders(0), + mExpandedFolders(0) + {} + virtual ~LLCheckFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + S32 getCollapsedFolders() { return mCollapsedFolders; } + S32 getExpandedFolders() { return mExpandedFolders; } + +private: + S32 mCollapsedFolders; + S32 mExpandedFolders; +}; + +// virtual +void LLCheckFolderState::doFolder(LLFolderViewFolder* folder) +{ + // Counting only folders that pass the filter. + // The listener check allow us to avoid counting the folder view + // object itself because it has no listener assigned. + if (folder->hasFilteredDescendants() && folder->getListener()) + { + if (folder->isOpen()) + { + ++mExpandedFolders; + } + else + { + ++mCollapsedFolders; + } + } +} + +/** + * Bridge to support knowing when the inventory has changed to update Landmarks tab + * ShowFolderState filter setting to show all folders when the filter string is empty and + * empty folder message when Landmarks inventory category has no children. */ class LLLandmarksPanelObserver : public LLInventoryObserver { @@ -89,7 +128,7 @@ private: void LLLandmarksPanelObserver::changed(U32 mask) { - mLP->saveFolderStateIfNoFilter(); + mLP->updateShowFolderState(); } LLLandmarksPanel::LLLandmarksPanel() @@ -134,22 +173,12 @@ BOOL LLLandmarksPanel::postBuild() getChild<LLAccordionCtrlTab>("tab_favorites")->setDisplayChildren(true); getChild<LLAccordionCtrlTab>("tab_landmarks")->setDisplayChildren(true); - gIdleCallbacks.addFunction(LLLandmarksPanel::doIdle, this); return TRUE; } // virtual void LLLandmarksPanel::onSearchEdit(const std::string& string) { - // show all folders in Landmarks Accordion for empty filter - if (mLandmarksInventoryPanel->getFilter()) - { - mLandmarksInventoryPanel->setShowFolderState(string.empty() ? - LLInventoryFilter::SHOW_ALL_FOLDERS : - LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS - ); - } - // give FolderView a chance to be refreshed. So, made all accordions visible for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) { @@ -162,7 +191,7 @@ void LLLandmarksPanel::onSearchEdit(const std::string& string) tab->changeOpenClose(false); } - LLInventorySubTreePanel* inventory_list = dynamic_cast<LLInventorySubTreePanel*>(tab->getAccordionView()); + LLPlacesInventoryPanel* inventory_list = dynamic_cast<LLPlacesInventoryPanel*>(tab->getAccordionView()); if (NULL == inventory_list) continue; if (inventory_list->getFilter()) @@ -173,6 +202,10 @@ void LLLandmarksPanel::onSearchEdit(const std::string& string) if (sFilterSubString != string) sFilterSubString = string; + + // show all folders in Landmarks Accordion for empty filter + // only if Landmarks inventory folder is not empty + updateShowFolderState(); } // virtual @@ -226,7 +259,7 @@ void LLLandmarksPanel::updateVerbs() updateListCommands(); } -void LLLandmarksPanel::onSelectionChange(LLInventorySubTreePanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action) +void LLLandmarksPanel::onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action) { if (user_action && (items.size() > 0)) { @@ -254,12 +287,21 @@ void LLLandmarksPanel::onSelectorButtonClicked() } } -void LLLandmarksPanel::saveFolderStateIfNoFilter() +void LLLandmarksPanel::updateShowFolderState() { - save_folder_state_if_no_filter(mFavoritesInventoryPanel); - save_folder_state_if_no_filter(mLandmarksInventoryPanel); - save_folder_state_if_no_filter(mMyInventoryPanel); - save_folder_state_if_no_filter(mLibraryInventoryPanel); + if (!mLandmarksInventoryPanel->getFilter()) + return; + + bool show_all_folders = mLandmarksInventoryPanel->getRootFolder()->getFilterSubString().empty(); + if (show_all_folders) + { + show_all_folders = category_has_descendents(mLandmarksInventoryPanel); + } + + mLandmarksInventoryPanel->setShowFolderState(show_all_folders ? + LLInventoryFilter::SHOW_ALL_FOLDERS : + LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS + ); } ////////////////////////////////////////////////////////////////////////// @@ -361,7 +403,7 @@ void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) void LLLandmarksPanel::initFavoritesInventoryPanel() { - mFavoritesInventoryPanel = getChild<LLInventorySubTreePanel>("favorites_list"); + mFavoritesInventoryPanel = getChild<LLPlacesInventoryPanel>("favorites_list"); initLandmarksPanel(mFavoritesInventoryPanel); mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems"); @@ -371,7 +413,7 @@ void LLLandmarksPanel::initFavoritesInventoryPanel() void LLLandmarksPanel::initLandmarksInventoryPanel() { - mLandmarksInventoryPanel = getChild<LLInventorySubTreePanel>("landmarks_list"); + mLandmarksInventoryPanel = getChild<LLPlacesInventoryPanel>("landmarks_list"); initLandmarksPanel(mLandmarksInventoryPanel); @@ -390,7 +432,7 @@ void LLLandmarksPanel::initLandmarksInventoryPanel() void LLLandmarksPanel::initMyInventoryPanel() { - mMyInventoryPanel= getChild<LLInventorySubTreePanel>("my_inventory_list"); + mMyInventoryPanel= getChild<LLPlacesInventoryPanel>("my_inventory_list"); initLandmarksPanel(mMyInventoryPanel); @@ -399,14 +441,14 @@ void LLLandmarksPanel::initMyInventoryPanel() void LLLandmarksPanel::initLibraryInventoryPanel() { - mLibraryInventoryPanel = getChild<LLInventorySubTreePanel>("library_list"); + mLibraryInventoryPanel = getChild<LLPlacesInventoryPanel>("library_list"); initLandmarksPanel(mLibraryInventoryPanel); initAccordion("tab_library", mLibraryInventoryPanel); } -void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_list) +void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list) { // In case of a dummy widget further we have no Folder View widget and no Filter, // so further initialization leads to crash. @@ -430,7 +472,7 @@ void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_lis inventory_list->saveFolderState(); } -void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list) +void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list) { LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name); @@ -440,7 +482,7 @@ void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLIn accordion_tab->setDisplayChildren(false); } -void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLInventorySubTreePanel* inventory_list) +void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list) { bool expanded = param.asBoolean(); @@ -466,7 +508,7 @@ void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLInvento } } -void LLLandmarksPanel::deselectOtherThan(const LLInventorySubTreePanel* inventory_list) +void LLLandmarksPanel::deselectOtherThan(const LLPlacesInventoryPanel* inventory_list) { if (inventory_list != mFavoritesInventoryPanel) { @@ -660,7 +702,12 @@ void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) } else if ("collapse_all" == command_name) { - root_folder->closeAllFolders(); + root_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + + // The top level folder is invisible, it must be open to + // display its sub-folders. + root_folder->openTopLevelFolders(); + root_folder->arrangeAll(); } else if ( "sort_by_date" == command_name) { @@ -722,6 +769,20 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const return false; } + LLCheckFolderState checker; + rootFolderView->applyFunctorRecursively(checker); + + // We assume that the root folder is always expanded so we enable "collapse_all" + // command when we have at least one more expanded folder. + if (checker.getExpandedFolders() < 2 && "collapse_all" == command_name) + { + return false; + } + + if (checker.getCollapsedFolders() < 1 && "expand_all" == command_name) + { + return false; + } if("category" == command_name) { @@ -778,46 +839,6 @@ void LLLandmarksPanel::onCustomAction(const LLSD& userdata) } } -void LLLandmarksPanel::updateFilteredAccordions() -{ - LLInventoryPanel* inventory_list = NULL; - LLAccordionCtrlTab* accordion_tab = NULL; - bool needs_arrange = false; - - for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) - { - accordion_tab = *iter; - - accordion_tab->setVisible(TRUE); - - inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView()); - if (NULL == inventory_list) continue; - - // This doesn't seem to work correctly. Disabling for now. -Seraph - // Enabled to show/hide accordions with/without landmarks. See EXT-2346. (Seth PE) - LLFolderView* fv = inventory_list->getRootFolder(); - - // arrange folder view contents to draw its descendants if it has any - fv->arrangeFromRoot(); - - bool has_descendants = fv->hasFilteredDescendants(); - if (!has_descendants) - needs_arrange = true; - - accordion_tab->setVisible(has_descendants); - - //accordion_tab->setVisible(TRUE); - } - - // we have to arrange accordion tabs for cases when filter string is less restrictive but - // all items are still filtered. - if (needs_arrange) - { - static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); - accordion->arrange(); - } -} - /* Processes such actions: cut/rename/delete/paste actions @@ -926,13 +947,6 @@ bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType carg return true; } -// static -void LLLandmarksPanel::doIdle(void* landmarks_panel) -{ - LLLandmarksPanel* panel = (LLLandmarksPanel* ) landmarks_panel; - panel->updateFilteredAccordions(); -} - void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark) { LLVector3d landmark_global_pos; @@ -1028,10 +1042,10 @@ void LLLandmarksPanel::doCreatePick(LLLandmark* landmark) ////////////////////////////////////////////////////////////////////////// // HELPER FUNCTIONS ////////////////////////////////////////////////////////////////////////// -static void filter_list(LLInventorySubTreePanel* inventory_list, const std::string& string) +static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string) { // When search is cleared, restore the old folder state. - if (string == "") + if (!inventory_list->getRootFolder()->getFilterSubString().empty() && string == "") { inventory_list->setFilterSubString(LLStringUtil::null); // Re-open folders that were open before @@ -1056,15 +1070,16 @@ static void filter_list(LLInventorySubTreePanel* inventory_list, const std::stri // Set new filter string inventory_list->setFilterSubString(string); - } -static void save_folder_state_if_no_filter(LLInventorySubTreePanel* inventory_list) +static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list) { - // save current folder open state if no filter currently applied - if (inventory_list->getRootFolder() && inventory_list->getRootFolder()->getFilterSubString().empty()) + LLViewerInventoryCategory* category = gInventory.getCategory(inventory_list->getStartFolderID()); + if (category) { - // inventory_list->saveFolderState(); // *TODO: commented out to fix build + return category->getDescendentCount() > 0; } + + return false; } // EOF diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index b0e537f647..569739237d 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -46,7 +46,7 @@ class LLAccordionCtrlTab; class LLFolderViewItem; class LLMenuGL; class LLInventoryPanel; -class LLInventorySubTreePanel; +class LLPlacesInventoryPanel; class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver { @@ -60,17 +60,18 @@ public: /*virtual*/ void onTeleport(); /*virtual*/ void updateVerbs(); - void onSelectionChange(LLInventorySubTreePanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action); + void onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action); void onSelectorButtonClicked(); - void setCurrentSelectedList(LLInventorySubTreePanel* inventory_list) + void setCurrentSelectedList(LLPlacesInventoryPanel* inventory_list) { mCurrentSelectedList = inventory_list; } /** - * Saves folder state for all Inventory Panels if there are no applied filter. + * Update filter ShowFolderState setting to show empty folder message + * if Landmarks inventory folder is empty. */ - void saveFolderStateIfNoFilter(); + void updateShowFolderState(); protected: /** @@ -92,10 +93,10 @@ private: void initLandmarksInventoryPanel(); void initMyInventoryPanel(); void initLibraryInventoryPanel(); - void initLandmarksPanel(LLInventorySubTreePanel* inventory_list); - void initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list); - void onAccordionExpandedCollapsed(const LLSD& param, LLInventorySubTreePanel* inventory_list); - void deselectOtherThan(const LLInventorySubTreePanel* inventory_list); + void initLandmarksPanel(LLPlacesInventoryPanel* inventory_list); + void initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list); + void onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list); + void deselectOtherThan(const LLPlacesInventoryPanel* inventory_list); // List Commands Handlers void initListCommandsHandlers(); @@ -112,13 +113,6 @@ private: void onCustomAction(const LLSD& command_name); /** - * Updates accordions according to filtered items in lists. - * - * It hides accordion for empty lists - */ - void updateFilteredAccordions(); - - /** * Determines if selected item can be modified via context/gear menu. * * It validates Places Landmarks rules first. And then LLFolderView permissions. @@ -133,11 +127,6 @@ private: bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); /** - * Static callback for gIdleCallbacks to perform actions out of drawing - */ - static void doIdle(void* landmarks_panel); - - /** * Landmark actions callbacks. Fire when a landmark is loaded from the list. */ void doShowOnMap(LLLandmark* landmark); @@ -148,14 +137,14 @@ private: void doCreatePick(LLLandmark* landmark); private: - LLInventorySubTreePanel* mFavoritesInventoryPanel; - LLInventorySubTreePanel* mLandmarksInventoryPanel; - LLInventorySubTreePanel* mMyInventoryPanel; - LLInventorySubTreePanel* mLibraryInventoryPanel; + LLPlacesInventoryPanel* mFavoritesInventoryPanel; + LLPlacesInventoryPanel* mLandmarksInventoryPanel; + LLPlacesInventoryPanel* mMyInventoryPanel; + LLPlacesInventoryPanel* mLibraryInventoryPanel; LLMenuGL* mGearLandmarkMenu; LLMenuGL* mGearFolderMenu; LLMenuGL* mMenuAdd; - LLInventorySubTreePanel* mCurrentSelectedList; + LLPlacesInventoryPanel* mCurrentSelectedList; LLInventoryObserver* mInventoryObserver; LLPanel* mListCommands; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index e5846c7318..5cc4d4aec6 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -965,6 +965,13 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) mFilterSubString = search_upper; + //store accordion tabs state before any manipulation with accordion tabs + if(!mFilterSubString.empty()) + { + notifyChildren(LLSD().with("action","store_state")); + } + + // Apply new filter. mNearbyList->setNameFilter(mFilterSubString); mOnlineFriendList->setNameFilter(mFilterSubString); @@ -976,6 +983,12 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) setAccordionCollapsedByUser("tab_all", false); showFriendsAccordionsIfNeeded(); + + //restore accordion tabs state _after_ all manipulations... + if(mFilterSubString.empty()) + { + notifyChildren(LLSD().with("action","restore_state")); + } } void LLPanelPeople::onTabSelected(const LLSD& param) @@ -984,6 +997,8 @@ void LLPanelPeople::onTabSelected(const LLSD& param) mNearbyListUpdater->setActive(tab_name == NEARBY_TAB_NAME); updateButtons(); + showFriendsAccordionsIfNeeded(); + if (GROUP_TAB_NAME == tab_name) mFilterEditor->setLabel(getString("groups_filter_label")); else diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 839452d061..7a4dd3569d 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -284,6 +284,7 @@ void LLPanelPickInfo::setPickName(const std::string& name) void LLPanelPickInfo::setPickDesc(const std::string& desc) { childSetValue(XML_DESC, desc); + updateContentPanelRect(); } void LLPanelPickInfo::setPickLocation(const std::string& location) @@ -291,6 +292,31 @@ void LLPanelPickInfo::setPickLocation(const std::string& location) childSetValue(XML_LOCATION, location); } +void LLPanelPickInfo::updateContentPanelRect() +{ + LLTextBox* desc = getChild<LLTextBox>(XML_DESC); + + S32 text_height = desc->getTextPixelHeight(); + LLRect text_rect = desc->getRect(); + + // let text-box height fit text height + text_rect.set(text_rect.mLeft, text_rect.mTop, text_rect.mRight, text_rect.mTop - text_height); + desc->setRect(text_rect); + desc->reshape(text_rect.getWidth(), text_rect.getHeight()); + // force reflow + desc->setText(desc->getText()); + + // bottom of description text-box will be bottom of content panel + desc->localRectToOtherView(desc->getLocalRect(), &text_rect, getChild<LLView>("profile_scroll")); + + LLPanel* content_panel = getChild<LLPanel>("scroll_content_panel"); + LLRect content_rect = content_panel->getRect(); + content_rect.set(content_rect.mLeft, content_rect.mTop, content_rect.mRight, text_rect.mBottom); + // Somehow setRect moves all elements down. + // Single reshape() updates rect and does not move anything. + content_panel->reshape(content_rect.getWidth(), content_rect.getHeight()); +} + void LLPanelPickInfo::onClickMap() { LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 95add387d0..12b5a116b4 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -140,6 +140,15 @@ protected: virtual LLVector3d& getPosGlobal() { return mPosGlobal; } /** + * Reshapes content panel to fit all elements. + * + * Assume that description text-box is the last element of panel. + * Reshape text-box to fit text height and then reshape content panel to fit + * text-box bottom. EXT-1326 + */ + void updateContentPanelRect(); + + /** * Callback for "Map" button, opens Map */ void onClickMap(); diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 596bd2909a..77c2fb7c8c 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -60,13 +60,18 @@ class LLTeleportHistoryFlatItem : public LLPanel { public: LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name, const std::string &hl); - virtual ~LLTeleportHistoryFlatItem() {}; + virtual ~LLTeleportHistoryFlatItem(); virtual BOOL postBuild(); + /*virtual*/ S32 notify(const LLSD& info); + S32 getIndex() { return mIndex; } void setIndex(S32 index) { mIndex = index; } const std::string& getRegionName() { return mRegionName;} + void setRegionName(const std::string& name); + void setHighlightedText(const std::string& text); + void updateTitle(); /*virtual*/ void setValue(const LLSD& value); @@ -75,18 +80,51 @@ public: virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); static void showPlaceInfoPanel(S32 index); + + LLHandle<LLTeleportHistoryFlatItem> getItemHandle() { mItemHandle.bind(this); return mItemHandle; } + private: void onProfileBtnClick(); LLButton* mProfileBtn; + LLTextBox* mTitle; LLTeleportHistoryPanel::ContextMenu *mContextMenu; S32 mIndex; std::string mRegionName; std::string mHighlight; + LLRootHandle<LLTeleportHistoryFlatItem> mItemHandle; }; +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +class LLTeleportHistoryFlatItemStorage: public LLSingleton<LLTeleportHistoryFlatItemStorage> { +protected: + typedef std::vector< LLHandle<LLTeleportHistoryFlatItem> > flat_item_list_t; + +public: + LLTeleportHistoryFlatItem* getFlatItemForPersistentItem ( + LLTeleportHistoryPanel::ContextMenu *context_menu, + const LLTeleportHistoryPersistentItem& persistent_item, + const S32 cur_item_index, + const std::string &hl); + + void removeItem(LLTeleportHistoryFlatItem* item); + + void purge(); + +private: + + flat_item_list_t mItems; +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name, const std::string &hl) : LLPanel(), mIndex(index), @@ -97,18 +135,37 @@ LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLTeleportHistor LLUICtrlFactory::getInstance()->buildPanel(this, "panel_teleport_history_item.xml"); } +LLTeleportHistoryFlatItem::~LLTeleportHistoryFlatItem() +{ +} + //virtual BOOL LLTeleportHistoryFlatItem::postBuild() { - LLTextUtil::textboxSetHighlightedVal(getChild<LLTextBox>("region"), LLStyle::Params(), mRegionName, mHighlight); + mTitle = getChild<LLTextBox>("region"); mProfileBtn = getChild<LLButton>("profile_btn"); mProfileBtn->setClickedCallback(boost::bind(&LLTeleportHistoryFlatItem::onProfileBtnClick, this)); + updateTitle(); + return true; } +S32 LLTeleportHistoryFlatItem::notify(const LLSD& info) +{ + if(info.has("detach")) + { + delete mMouseDownSignal; + mMouseDownSignal = NULL; + delete mRightMouseDownSignal; + mRightMouseDownSignal = NULL; + return 1; + } + return 0; +} + void LLTeleportHistoryFlatItem::setValue(const LLSD& value) { if (!value.isMap()) return;; @@ -116,6 +173,25 @@ void LLTeleportHistoryFlatItem::setValue(const LLSD& value) childSetVisible("selected_icon", value["selected"]); } +void LLTeleportHistoryFlatItem::setHighlightedText(const std::string& text) +{ + mHighlight = text; +} + +void LLTeleportHistoryFlatItem::setRegionName(const std::string& name) +{ + mRegionName = name; +} + +void LLTeleportHistoryFlatItem::updateTitle() +{ + LLTextUtil::textboxSetHighlightedVal( + mTitle, + LLStyle::Params(), + mRegionName, + mHighlight); +} + void LLTeleportHistoryFlatItem::onMouseEnter(S32 x, S32 y, MASK mask) { childSetVisible("hovered_icon", true); @@ -155,6 +231,82 @@ void LLTeleportHistoryFlatItem::onProfileBtnClick() LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex); } +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +LLTeleportHistoryFlatItem* +LLTeleportHistoryFlatItemStorage::getFlatItemForPersistentItem ( + LLTeleportHistoryPanel::ContextMenu *context_menu, + const LLTeleportHistoryPersistentItem& persistent_item, + const S32 cur_item_index, + const std::string &hl) +{ + LLTeleportHistoryFlatItem* item = NULL; + if ( cur_item_index < (S32) mItems.size() ) + { + item = mItems[cur_item_index].get(); + if (item->getParent() == NULL) + { + item->setIndex(cur_item_index); + item->setRegionName(persistent_item.mTitle); + item->setHighlightedText(hl); + item->setVisible(TRUE); + item->updateTitle(); + } + else + { + // Item already added to parent + item = NULL; + } + } + + if ( !item ) + { + item = new LLTeleportHistoryFlatItem(cur_item_index, + context_menu, + persistent_item.mTitle, + hl); + mItems.push_back(item->getItemHandle()); + } + + return item; +} + +void LLTeleportHistoryFlatItemStorage::removeItem(LLTeleportHistoryFlatItem* item) +{ + if (item) + { + flat_item_list_t::iterator item_iter = std::find(mItems.begin(), + mItems.end(), + item->getItemHandle()); + if (item_iter != mItems.end()) + { + mItems.erase(item_iter); + } + } +} + +void LLTeleportHistoryFlatItemStorage::purge() +{ + for ( flat_item_list_t::iterator + it = mItems.begin(), + it_end = mItems.end(); + it != it_end; ++it ) + { + LLHandle <LLTeleportHistoryFlatItem> item_handle = *it; + if ( !item_handle.isDead() && item_handle.get()->getParent() == NULL ) + { + item_handle.get()->die(); + } + } + mItems.clear(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + LLTeleportHistoryPanel::ContextMenu::ContextMenu() : mMenu(NULL) { @@ -236,6 +388,7 @@ LLTeleportHistoryPanel::LLTeleportHistoryPanel() LLTeleportHistoryPanel::~LLTeleportHistoryPanel() { + LLTeleportHistoryFlatItemStorage::instance().purge(); LLView::deleteViewByHandle(mGearMenuHandle); } @@ -478,16 +631,15 @@ void LLTeleportHistoryPanel::refresh() while (mCurrentItem >= 0) { // Filtering - std::string landmark_title = items[mCurrentItem].mTitle; - LLStringUtil::toUpper(landmark_title); - - std::string::size_type match_offset = sFilterSubString.size() ? landmark_title.find(sFilterSubString) : std::string::npos; - bool passed = sFilterSubString.size() == 0 || match_offset != std::string::npos; - - if (!passed) + if (!sFilterSubString.empty()) { - mCurrentItem--; - continue; + std::string landmark_title(items[mCurrentItem].mTitle); + LLStringUtil::toUpper(landmark_title); + if( std::string::npos == landmark_title.find(sFilterSubString) ) + { + mCurrentItem--; + continue; + } } // Checking whether date of item is earlier, than tab_boundary_date. @@ -507,6 +659,9 @@ void LLTeleportHistoryPanel::refresh() // Expand all accordion tabs when filtering if(!sFilterSubString.empty()) { + //store accordion tab state when filter is not empty + tab->notifyChildren(LLSD().with("action","store_state")); + tab->setDisplayChildren(true); } // Restore each tab's expand state when not filtering @@ -514,6 +669,9 @@ void LLTeleportHistoryPanel::refresh() { bool collapsed = isAccordionCollapsedByUser(tab); tab->setDisplayChildren(!collapsed); + + //restore accordion state after all those accodrion tabmanipulations + tab->notifyChildren(LLSD().with("action","restore_state")); } curr_flat_view = getFlatListViewFromTab(tab); @@ -521,9 +679,14 @@ void LLTeleportHistoryPanel::refresh() if (curr_flat_view) { - LLTeleportHistoryFlatItem* item = new LLTeleportHistoryFlatItem(mCurrentItem, &mContextMenu, items[mCurrentItem].mTitle, sFilterSubString); - curr_flat_view->addItem(item); - + LLTeleportHistoryFlatItem* item = + LLTeleportHistoryFlatItemStorage::instance() + .getFlatItemForPersistentItem(&mContextMenu, + items[mCurrentItem], + mCurrentItem, + sFilterSubString); + if ( !curr_flat_view->addItem(item, LLUUID::null, ADD_BOTTOM, false) ) + llerrs << "Couldn't add flat item to teleport history." << llendl; if (mLastSelectedItemIndex == mCurrentItem) curr_flat_view->selectItem(item, true); } @@ -534,6 +697,16 @@ void LLTeleportHistoryPanel::refresh() break; } + for (S32 n = mItemContainers.size() - 1; n >= 0; --n) + { + LLAccordionCtrlTab* tab = mItemContainers.get(n); + LLFlatListView* fv = getFlatListViewFromTab(tab); + if (fv) + { + fv->notify(LLSD().with("rearrange", LLSD())); + } + } + mHistoryAccordion->arrange(); updateVerbs(); @@ -566,11 +739,12 @@ void LLTeleportHistoryPanel::replaceItem(S32 removed_index) } const LLTeleportHistoryStorage::slurl_list_t& history_items = mTeleportHistory->getItems(); - LLTeleportHistoryFlatItem* item = new LLTeleportHistoryFlatItem(history_items.size(), // index will be decremented inside loop below - &mContextMenu, - history_items[history_items.size() - 1].mTitle, // Most recent item, it was - sFilterSubString); - // added instead of removed + LLTeleportHistoryFlatItem* item = LLTeleportHistoryFlatItemStorage::instance() + .getFlatItemForPersistentItem(&mContextMenu, + history_items[history_items.size() - 1], // Most recent item, it was added instead of removed + history_items.size(), // index will be decremented inside loop below + sFilterSubString); + fv->addItem(item, LLUUID::null, ADD_TOP); // Index of each item, from last to removed item should be decremented @@ -598,6 +772,8 @@ void LLTeleportHistoryPanel::replaceItem(S32 removed_index) if (item->getIndex() == removed_index) { + LLTeleportHistoryFlatItemStorage::instance().removeItem(item); + fv->removeItem(item); // If flat list becames empty, then accordion tab should be hidden @@ -629,10 +805,12 @@ void LLTeleportHistoryPanel::showTeleportHistory() LLFlatListView* fv = getFlatListViewFromTab(tab); if (fv) - fv->clear(); + { + // Detached panels are managed by LLTeleportHistoryFlatItemStorage + std::vector<LLPanel*> detached_items; + fv->detachItems(detached_items); + } } - - refresh(); } void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected) diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 5941487c7d..330e220af3 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -57,6 +57,7 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av mSortOrder(E_SORT_BY_NAME) , mParticipantListMenu(NULL) , mExcludeAgent(exclude_agent) +, mValidateSpeakerCallback(NULL) { mSpeakerAddListener = new SpeakerAddListener(*this); mSpeakerRemoveListener = new SpeakerRemoveListener(*this); @@ -86,22 +87,23 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av } //Lets fill avatarList with existing speakers - LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); - LLSpeakerMgr::speaker_list_t speaker_list; mSpeakerMgr->getSpeakerList(&speaker_list, true); for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) { const LLPointer<LLSpeaker>& speakerp = *it; - addAvatarIDExceptAgent(group_members, speakerp->mID); + addAvatarIDExceptAgent(speakerp->mID); if ( speakerp->mIsModerator ) { mModeratorList.insert(speakerp->mID); } + else + { + mModeratorToRemoveList.insert(speakerp->mID); + } } // we need to exclude agent id for non group chat - mAvatarList->setDirty(true); sort(); } @@ -161,7 +163,7 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param) { std::string name = item->getAvatarName(); size_t found = name.find(moderator_indicator); - if (found == std::string::npos) + if (found != std::string::npos) { name.erase(found, moderator_indicator_len); item->setName(name); @@ -208,31 +210,32 @@ LLParticipantList::EParticipantSortOrder LLParticipantList::getSortOrder() return mSortOrder; } +void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb) +{ + mValidateSpeakerCallback = cb; +} + void LLParticipantList::updateRecentSpeakersOrder() { if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder()) { + // Need to update speakers to sort list correctly + mSpeakerMgr->update(true); // Resort avatar list - mAvatarList->setDirty(true); sort(); } } bool LLParticipantList::onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { - LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); LLUUID uu_id = event->getValue().asUUID(); - LLAvatarList::uuid_vector_t::iterator found = std::find(group_members.begin(), group_members.end(), uu_id); - if(found != group_members.end()) + if (mValidateSpeakerCallback && mValidateSpeakerCallback(uu_id)) { - llinfos << "Already got a buddy" << llendl; return true; } - addAvatarIDExceptAgent(group_members, uu_id); - // Mark AvatarList as dirty one - mAvatarList->setDirty(); + addAvatarIDExceptAgent(uu_id); sort(); return true; } @@ -330,11 +333,13 @@ void LLParticipantList::sort() } } -void LLParticipantList::addAvatarIDExceptAgent(std::vector<LLUUID>& existing_list, const LLUUID& avatar_id) +void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) { if (mExcludeAgent && gAgent.getID() == avatar_id) return; + if (mAvatarList->contains(avatar_id)) return; - existing_list.push_back(avatar_id); + mAvatarList->getIDs().push_back(avatar_id); + mAvatarList->setDirty(); adjustParticipant(avatar_id); } @@ -354,7 +359,7 @@ bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::L { /** * We need to filter speaking objects. These objects shouldn't appear in the list - * @c LLFloaterChat::addChat() in llviewermessage.cpp to get detailed call hierarchy + * @see LLFloaterChat::addChat() in llviewermessage.cpp to get detailed call hierarchy */ const LLUUID& speaker_id = event->getValue().asUUID(); LLPointer<LLSpeaker> speaker = mParent.mSpeakerMgr->findSpeaker(speaker_id); @@ -576,33 +581,46 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& { return mUUIDs.front() != gAgentID; } - else - if (item == "can_allow_text_chat" || "can_moderate_voice" == item) + else if (item == "can_allow_text_chat") + { + return isGroupModerator(); + } + else if ("can_moderate_voice" == item) + { + if (isGroupModerator()) { - return isGroupModerator(); + LLPointer<LLSpeaker> speakerp = mParent.mSpeakerMgr->findSpeaker(mUUIDs.front()); + if (speakerp.notNull()) + { + // not in voice participants can not be moderated + return speakerp->mStatus == LLSpeaker::STATUS_VOICE_ACTIVE + || speakerp->mStatus == LLSpeaker::STATUS_MUTED; + } } + return false; + } else if (item == std::string("can_add")) - { - // We can add friends if: - // - there are selected people - // - and there are no friends among selection yet. + { + // We can add friends if: + // - there are selected people + // - and there are no friends among selection yet. - bool result = (mUUIDs.size() > 0); + bool result = (mUUIDs.size() > 0); - std::vector<LLUUID>::const_iterator - id = mUUIDs.begin(), - uuids_end = mUUIDs.end(); + std::vector<LLUUID>::const_iterator + id = mUUIDs.begin(), + uuids_end = mUUIDs.end(); - for (;id != uuids_end; ++id) + for (;id != uuids_end; ++id) + { + if ( LLAvatarActions::isFriend(*id) ) { - if ( LLAvatarActions::isFriend(*id) ) - { - result = false; - break; - } + result = false; + break; } - return result; } + return result; + } else if (item == "can_call") { return LLVoiceClient::voiceEnabled(); diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h index c4eb180917..d15ec980db 100644 --- a/indra/newview/llparticipantlist.h +++ b/indra/newview/llparticipantlist.h @@ -44,6 +44,9 @@ class LLParticipantList { LOG_CLASS(LLParticipantList); public: + + typedef boost::function<bool (const LLUUID& speaker_id)> validate_speaker_callback_t; + LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu = true, bool exclude_agent = true); ~LLParticipantList(); void setSpeakingIndicatorsVisible(BOOL visible); @@ -54,6 +57,13 @@ class LLParticipantList } EParticipantSortOrder; /** + * Adds specified avatar ID to the existing list if it is not Agent's ID + * + * @param[in] avatar_id - Avatar UUID to be added into the list + */ + void addAvatarIDExceptAgent(const LLUUID& avatar_id); + + /** * Set and sort Avatarlist by given order */ void setSortOrder(EParticipantSortOrder order = E_SORT_BY_NAME); @@ -64,6 +74,15 @@ class LLParticipantList */ void updateRecentSpeakersOrder(); + /** + * Set a callback to be called before adding a speaker. Invalid speakers will not be added. + * + * If the callback is unset all speakers are considered as valid. + * + * @see onAddItemEvent() + */ + void setValidateSpeakerCallback(validate_speaker_callback_t cb); + protected: /** * LLSpeakerMgr event handlers @@ -218,14 +237,6 @@ class LLParticipantList void onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param); /** - * Adds specified avatar ID to the existing list if it is not Agent's ID - * - * @param[in, out] existing_list - vector with avatars' UUIDs already in the list - * @param[in] avatar_id - Avatar UUID to be added into the list - */ - void addAvatarIDExceptAgent(std::vector<LLUUID>& existing_list, const LLUUID& avatar_id); - - /** * Adjusts passed participant to work properly. * * Adds SpeakerMuteListener to process moderation actions. @@ -260,4 +271,5 @@ class LLParticipantList boost::signals2::connection mAvatarListReturnConnection; LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers; + validate_speaker_callback_t mValidateSpeakerCallback; }; diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp new file mode 100644 index 0000000000..4de953a59d --- /dev/null +++ b/indra/newview/llplacesinventorypanel.cpp @@ -0,0 +1,191 @@ +/** + * @file llplacesinventorypanel.cpp + * @brief LLPlacesInventoryPanel class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 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 "llscrollcontainer.h" + +#include "llplacesinventorypanel.h" + +#include "llfoldervieweventlistener.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llpanellandmarks.h" +#include "llplacesinventorybridge.h" + +static LLDefaultChildRegistry::Register<LLPlacesInventoryPanel> r("places_inventory_panel"); + +static const LLPlacesInventoryBridgeBuilder PLACES_INVENTORY_BUILDER; + +LLPlacesInventoryPanel::LLPlacesInventoryPanel(const Params& p) : + LLInventoryPanel(p), + mSavedFolderState(NULL) + +{ + mInvFVBridgeBuilder = &PLACES_INVENTORY_BUILDER; + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); +} + + +LLPlacesInventoryPanel::~LLPlacesInventoryPanel() +{ + delete mSavedFolderState; +} + +BOOL LLPlacesInventoryPanel::postBuild() +{ + LLInventoryPanel::postBuild(); + + // clear Contents(); + { + mFolders->destroyView(); + mFolders->getParent()->removeChild(mFolders); + mFolders->die(); + + if( mScroller ) + { + removeChild( mScroller ); + mScroller->die(); + mScroller = NULL; + } + mFolders = NULL; + } + + + mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves + + // create root folder + { + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + LLPlacesFolderView::Params p; + p.name = getName(); + p.rect = folder_rect; + p.parent_panel = this; + mFolders = (LLFolderView*)LLUICtrlFactory::create<LLPlacesFolderView>(p); + mFolders->setAllowMultiSelect(mAllowMultiSelect); + } + + mCommitCallbackRegistrar.popScope(); + + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // scroller + { + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params p; + p.name("Inventory Scroller"); + p.rect(scroller_view_rect); + p.follows.flags(FOLLOWS_ALL); + p.reserve_scroll_corner(true); + p.tab_stop(true); + mScroller = LLUICtrlFactory::create<LLScrollContainer>(p); + } + addChild(mScroller); + mScroller->addChild(mFolders); + + mFolders->setScrollContainer(mScroller); + + + // cut subitems + mFolders->setUseEllipses(true); + + return TRUE; +} + +// save current folder open state +void LLPlacesInventoryPanel::saveFolderState() +{ + mSavedFolderState->setApply(FALSE); + getRootFolder()->applyFunctorRecursively(*mSavedFolderState); +} + +// re-open folders which state was saved +void LLPlacesInventoryPanel::restoreFolderState() +{ + mSavedFolderState->setApply(TRUE); + getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + getRootFolder()->applyFunctorRecursively(opener); + getRootFolder()->scrollToShowSelection(); +} + +/************************************************************************/ +/* PROTECTED METHODS */ +/************************************************************************/ + + + +/************************************************************************/ +/* LLPlacesFolderView implementation */ +/************************************************************************/ + +////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS +////////////////////////////////////////////////////////////////////////// + +BOOL LLPlacesFolderView::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + // let children to change selection first + childrenHandleRightMouseDown(x, y, mask); + mParentLandmarksPanel->setCurrentSelectedList((LLPlacesInventoryPanel*)getParentPanel()); + + // then determine its type and set necessary menu handle + if (getCurSelectedItem()) + { + LLInventoryType::EType inventory_type = getCurSelectedItem()->getListener()->getInventoryType(); + inventory_type_menu_handle_t::iterator it_handle = mMenuHandlesByInventoryType.find(inventory_type); + + if (it_handle != mMenuHandlesByInventoryType.end()) + { + mPopupMenuHandle = (*it_handle).second; + } + else + { + llwarns << "Requested menu handle for non-setup inventory type: " << inventory_type << llendl; + } + + } + + return LLFolderView::handleRightMouseDown(x, y, mask); +} + +void LLPlacesFolderView::setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle) +{ + mMenuHandlesByInventoryType[asset_type] = menu_handle; +} + +// EOF diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h new file mode 100644 index 0000000000..7b34045d32 --- /dev/null +++ b/indra/newview/llplacesinventorypanel.h @@ -0,0 +1,96 @@ +/** + * @file llplacesinventorypanel.h + * @brief LLPlacesInventoryPanel class declaration + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 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_LLINVENTORYSUBTREEPANEL_H +#define LL_LLINVENTORYSUBTREEPANEL_H + +#include "llfloaterinventory.h" +#include "llinventorypanel.h" +#include "llfolderview.h" + +class LLLandmarksPanel; + +class LLPlacesInventoryPanel : public LLInventoryPanel +{ +public: + struct Params + : public LLInitParam::Block<Params, LLInventoryPanel::Params> + { + Params() + {} + }; + + LLPlacesInventoryPanel(const Params& p); + ~LLPlacesInventoryPanel(); + + /*virtual*/ BOOL postBuild(); + + void saveFolderState(); + void restoreFolderState(); + +private: + LLSaveFolderState* mSavedFolderState; +}; + + +class LLPlacesFolderView : public LLFolderView +{ +public: + LLPlacesFolderView(const LLFolderView::Params& p) : LLFolderView(p) {}; + /** + * Handles right mouse down + * + * Contains workaround for EXT-2786: sets current selected list for landmark + * panel using @c mParentLandmarksPanel which is set in @c LLLandmarksPanel::initLandmarksPanel + */ + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + + void setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle); + + void setParentLandmarksPanel(LLLandmarksPanel* panel) + { + mParentLandmarksPanel = panel; + } + + S32 getSelectedCount() { return (S32)mSelectedItems.size(); } + +private: + /** + * holds pointer to landmark panel. This pointer is used in @c LLPlacesFolderView::handleRightMouseDown + */ + LLLandmarksPanel* mParentLandmarksPanel; + typedef std::map<LLInventoryType::EType, LLHandle<LLView> > inventory_type_menu_handle_t; + inventory_type_menu_handle_t mMenuHandlesByInventoryType; + +}; + +#endif //LL_LLINVENTORYSUBTREEPANEL_H diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index bd256ec9c2..8c3f3dc5fb 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -217,7 +217,10 @@ void LLScreenChannel::addToast(const LLToast::Params& p) ToastElem new_toast_elem(p); + // reset HIDDEN flags for the Overflow Toast mOverflowToastHidden = false; + if(mOverflowToastPanel) + mOverflowToastPanel->setIsHidden(false); new_toast_elem.toast->setOnFadeCallback(boost::bind(&LLScreenChannel::onToastFade, this, _1)); new_toast_elem.toast->setOnToastDestroyedCallback(boost::bind(&LLScreenChannel::onToastDestroyed, this, _1)); @@ -459,7 +462,7 @@ void LLScreenChannel::showToastsBottom() S32 toast_margin = 0; std::vector<ToastElem>::reverse_iterator it; - closeOverflowToastPanel(); + LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get()); for(it = mToastList.rbegin(); it != mToastList.rend(); ++it) { @@ -473,6 +476,16 @@ void LLScreenChannel::showToastsBottom() toast_rect.setOriginAndSize(getRect().mLeft, bottom + toast_margin, toast_rect.getWidth() ,toast_rect.getHeight()); (*it).toast->setRect(toast_rect); + // don't show toasts if there is not enough space + if(floater && floater->overlapsScreenChannel()) + { + LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); + if(toast_rect.mTop + getOverflowToastHeight() + toast_margin > world_rect.mTop) + { + break; + } + } + bool stop_showing_toasts = (*it).toast->getRect().mTop > getRect().mTop; if(!stop_showing_toasts) @@ -513,7 +526,11 @@ void LLScreenChannel::showToastsBottom() mHiddenToastsNum++; } createOverflowToast(bottom, gSavedSettings.getS32("NotificationTipToastLifeTime")); - } + } + else + { + closeOverflowToastPanel(); + } } //-------------------------------------------------------------------------- @@ -544,11 +561,14 @@ void LLScreenChannel::createOverflowToast(S32 bottom, F32 timer) LLRect toast_rect; LLToast::Params p; p.lifetime_secs = timer; - mOverflowToastPanel = new LLToast(p); + + if(!mOverflowToastPanel) + mOverflowToastPanel = new LLToast(p); if(!mOverflowToastPanel) return; + mOverflowToastPanel->startFading(); mOverflowToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onOverflowToastHide, this)); LLTextBox* text_box = mOverflowToastPanel->getChild<LLTextBox>("toast_text"); @@ -567,6 +587,18 @@ void LLScreenChannel::createOverflowToast(S32 bottom, F32 timer) toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastGap"), getRect().getWidth(), toast_rect.getHeight()); mOverflowToastPanel->setRect(toast_rect); + // don't show overflow toast if there is not enough space for it. + LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get()); + if(floater && floater->overlapsScreenChannel()) + { + LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); + if(toast_rect.mTop > world_rect.mTop) + { + closeOverflowToastPanel(); + return; + } + } + text_box->setValue(text); text_box->setVisible(TRUE); @@ -606,8 +638,8 @@ void LLScreenChannel::closeOverflowToastPanel() { if(mOverflowToastPanel != NULL) { - mOverflowToastPanel->closeFloater(); - mOverflowToastPanel = NULL; + mOverflowToastPanel->setVisible(FALSE); + mOverflowToastPanel->stopFading(); } } @@ -656,6 +688,24 @@ F32 LLScreenChannel::getHeightRatio() return ratio; } +S32 LLScreenChannel::getOverflowToastHeight() +{ + if(mOverflowToastPanel) + { + return mOverflowToastPanel->getRect().getHeight(); + } + + static S32 height = 0; + if(0 == height) + { + LLToast::Params p; + LLToast* toast = new LLToast(p); + height = toast->getRect().getHeight(); + delete toast; + } + return height; +} + //-------------------------------------------------------------------------- void LLScreenChannel::updateStartUpString(S32 num) { @@ -814,25 +864,22 @@ void LLScreenChannel::updateShowToastsState() return; } - // for Message Well floater showed in a docked state - adjust channel's height - if(dynamic_cast<LLSysWellWindow*>(floater) || dynamic_cast<LLIMFloater*>(floater) - || dynamic_cast<LLScriptFloater*>(floater)) + S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");; + LLRect this_rect = getRect(); + + // adjust channel's height + if(floater->overlapsScreenChannel()) { - S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");; - LLRect this_rect = getRect(); - if(floater->getVisible() && floater->isDocked()) + channel_bottom += floater->getRect().getHeight(); + if(floater->getDockControl()) { - channel_bottom += floater->getRect().getHeight(); - if(floater->getDockControl()) - { - channel_bottom += floater->getDockControl()->getTongueHeight(); - } + channel_bottom += floater->getDockControl()->getTongueHeight(); } + } - if(channel_bottom != this_rect.mBottom) - { - setRect(LLRect(this_rect.mLeft, this_rect.mTop, this_rect.mRight, channel_bottom)); - } + if(channel_bottom != this_rect.mBottom) + { + setRect(LLRect(this_rect.mLeft, this_rect.mTop, this_rect.mRight, channel_bottom)); } } diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index 321fb244a1..38f27f756b 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -281,6 +281,8 @@ private: */ static F32 getHeightRatio(); + S32 getOverflowToastHeight(); + // Channel's flags static bool mWasStartUpToastShown; diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index 1962d871a6..cf62d47362 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -67,6 +67,7 @@ LLScriptFloater::LLScriptFloater(const LLSD& key) , mScriptForm(NULL) { setMouseDownCallback(boost::bind(&LLScriptFloater::onMouseDown, this)); + setOverlapsScreenChannel(true); } bool LLScriptFloater::toggle(const LLUUID& object_id) diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp index 90214a1bd7..8f2c877c7a 100644 --- a/indra/newview/llspeakbutton.cpp +++ b/indra/newview/llspeakbutton.cpp @@ -123,7 +123,7 @@ LLSpeakButton::LLSpeakButton(const Params& p) mOutputMonitor->setIsAgentControl(true); //*TODO find a better place to do that - LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::sOnCurrentChannelChanged, _1)); + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::sOnCurrentChannelChanged, _1), true); } LLSpeakButton::~LLSpeakButton() diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 91b417c61f..010dfd1b33 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -615,6 +615,9 @@ private: void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { + LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); + if (!speakerp) return; + std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); LLSD data; data["method"] = "mute update"; @@ -623,7 +626,7 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) data["params"]["agent_id"] = speaker_id; data["params"]["mute_info"] = LLSD::emptyMap(); //current value represents ability to type, so invert - data["params"]["mute_info"]["text"] = !findSpeaker(speaker_id)->mModeratorMutedText; + data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; LLHTTPClient::post(url, data, new ModerationResponder(getSessionID())); } diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 9e72464237..23c4f00ab7 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -160,6 +160,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect) mBtnVolume = getChild<LLButton>( "volume_btn" ); mBtnVolume->setClickedCallback( onClickVolume, this ); mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this)); + mBtnVolume->setIsChrome(TRUE); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2)); diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 8c6ea59407..bcaefc3690 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -63,6 +63,7 @@ LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key) { mTypedItemsCount[IT_NOTIFICATION] = 0; mTypedItemsCount[IT_INSTANT_MESSAGE] = 0; + setOverlapsScreenChannel(true); } //--------------------------------------------------------------------------------- @@ -743,9 +744,13 @@ BOOL LLIMWellWindow::postBuild() void LLIMWellWindow::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { - if (mMessageList->getItemByValue(session_id)) return; + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (!session) return; + + // no need to spawn chiclets for participants in P2P calls called through Avaline + if (session->isP2P() && session->isOtherParticipantAvaline()) return; - if (!gIMMgr->hasSession(session_id)) return; + if (mMessageList->getItemByValue(session_id)) return; addIMRow(session_id, 0, name, other_participant_id); reshapeWindow(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 5f7c2f5080..25e5e23e6f 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1237,6 +1237,7 @@ void LLTextureCtrl::draw() // Using the discard level, do not show the string if the texture is almost but not // fully loaded. if ( mTexturep.notNull() && + (!mTexturep->isFullyLoaded()) && (mShowLoadingPlaceholder == TRUE) && (mTexturep->getDiscardLevel() != 1) && (mTexturep->getDiscardLevel() != 0)) diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 0b232da62b..fb1d591e32 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -45,7 +45,7 @@ class LLButton; class LLFloaterTexturePicker; class LLInventoryItem; -class LLViewerTexture; +class LLViewerFetchedTexture; // used for setting drag & drop callbacks. typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback; @@ -189,7 +189,7 @@ private: drag_n_drop_callback mDropCallback; commit_callback_t mOnCancelCallback; commit_callback_t mOnSelectCallback; - LLPointer<LLViewerTexture> mTexturep; + LLPointer<LLViewerFetchedTexture> mTexturep; LLUIColor mBorderColor; LLUUID mImageItemID; LLUUID mImageAssetID; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e80dafe245..a75f631769 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -801,7 +801,7 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == SEND_HTTP_REQ) { { - const S32 HTTP_QUEUE_MAX_SIZE = 32; + const S32 HTTP_QUEUE_MAX_SIZE = 8; // *TODO: Integrate this with llviewerthrottle // Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP, // but probably not for Textures. @@ -842,10 +842,10 @@ bool LLTextureFetchWorker::doWork(S32 param) mLoaded = FALSE; mGetStatus = 0; mGetReason.clear(); - lldebugs << "HTTP GET: " << mID << " Offset: " << offset - << " Bytes: " << mRequestedSize - << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth - << llendl; + LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset + << " Bytes: " << mRequestedSize + << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth + << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); mState = WAIT_HTTP_REQ; @@ -874,12 +874,30 @@ bool LLTextureFetchWorker::doWork(S32 param) S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; if (mRequestedSize < 0) { - const S32 HTTP_MAX_RETRY_COUNT = 3; - S32 max_attempts = (mGetStatus == HTTP_NOT_FOUND) ? 1 : HTTP_MAX_RETRY_COUNT + 1; - llinfos << "HTTP GET failed for: " << mUrl - << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'" - << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; - ++mHTTPFailCount; + S32 max_attempts; + if (mGetStatus == HTTP_NOT_FOUND) + { + mHTTPFailCount = max_attempts = 1; // Don't retry + llinfos << "Texture missing from server (404): " << mUrl << llendl; + } + else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE) + { + // *TODO: Should probably introduce a timer here to delay future HTTP requsts + // for a short time (~1s) to ease server load? Ideally the server would queue + // requests instead of returning 503... we already limit the number pending. + ++mHTTPFailCount; + max_attempts = mHTTPFailCount+1; // Keep retrying + LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; + } + else + { + const S32 HTTP_MAX_RETRY_COUNT = 3; + max_attempts = HTTP_MAX_RETRY_COUNT + 1; + ++mHTTPFailCount; + llinfos << "HTTP GET failed for: " << mUrl + << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'" + << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; + } if (mHTTPFailCount >= max_attempts) { if (cur_size > 0) @@ -1239,7 +1257,7 @@ void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, gTextureList.sTextureBits += data_size * 8; // Approximate - does not include header bits - //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl; + LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; if (data_size > 0) { // *TODO: set the formatted image data here directly to avoid the copy @@ -1432,8 +1450,9 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) { // Only do partial requests for J2C at the moment - //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl; + //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl; desired_size = MAX_IMAGE_DATA_SIZE; + desired_discard = 0; } else if (desired_discard == 0) { diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index c48301fa1e..c3ccb9380b 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -279,7 +279,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight()); mLineEditor->setRect(leditor_rect); mLineEditor->setText(edit_text_contents); - mLineEditor->setMaxTextLength(STD_STRING_STR_LEN); + mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1); // make sure all edit keys get handled properly (DEV-22396) mLineEditor->setHandleEditKeysDirectly(TRUE); @@ -385,6 +385,12 @@ BOOL LLToastAlertPanel::handleKeyHere(KEY key, MASK mask ) { if( KEY_RETURN == key && mask == MASK_NONE ) { + LLButton* defaultBtn = getDefaultButton(); + if(defaultBtn && defaultBtn->getVisible() && defaultBtn->getEnabled()) + { + // If we have a default button, click it when return is pressed + defaultBtn->onCommit(); + } return TRUE; } else if (KEY_RIGHT == key) diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index b7add03e0e..d62017cc2f 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -35,13 +35,14 @@ #include "llnotifications.h" #include "llinstantmessage.h" +#include "llviewerchat.h" const S32 LLToastIMPanel::DEFAULT_MESSAGE_MAX_LINE_COUNT = 6; //-------------------------------------------------------------------------- LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notification), - mAvatar(NULL), mUserName(NULL), - mTime(NULL), mMessage(NULL) + mAvatar(NULL), mUserName(NULL), + mTime(NULL), mMessage(NULL) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_instant_message.xml"); @@ -52,8 +53,11 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif mMessage = getChild<LLTextBox>("message"); LLStyle::Params style_params; - style_params.font.name(LLFontGL::nameFromFont(style_params.font)); - style_params.font.size(LLFontGL::sizeFromFont(style_params.font)); + LLFontGL* fontp = LLViewerChat::getChatFont(); + std::string font_name = LLFontGL::nameFromFont(fontp); + std::string font_size = LLFontGL::sizeFromFont(fontp); + style_params.font.name(font_name); + style_params.font.size(font_size); style_params.font.style = "UNDERLINE"; //Handle IRC styled /me messages. @@ -63,13 +67,16 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif mMessage->clear(); style_params.font.style ="ITALIC"; - mMessage->appendText(p.from + " ", FALSE, style_params); + mMessage->appendText(p.from, FALSE, style_params); style_params.font.style = "ITALIC"; mMessage->appendText(p.message.substr(3), FALSE, style_params); } else + { mMessage->setValue(p.message); + } + mUserName->setValue(p.from); mTime->setValue(p.time); mSessionID = p.session_id; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index df62c9628d..4d912c6c11 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -166,8 +166,11 @@ public: // 2xx status codes indicate success. // Most 4xx status codes are successful enough for our purposes. // 499 is the error code for host not found, timeout, etc. + // 500 means "Internal Server error" but we decided it's okay to + // accept this and go past it in the MIME type probe if( ((status >= 200) && (status < 300)) || - ((status >= 400) && (status < 499)) ) + ((status >= 400) && (status < 499)) || + (status == 500) ) { // The probe was successful. diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index 90cfb85821..e9293ac5a4 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -1,7 +1,7 @@ /** * @file llviewermedia_streamingaudio.h * @author Tofu Linden, Sam Kolb - * @brief LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugins API. + * @brief LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugin API. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "llpluginclassmedia.h" +#include "llpluginclassmediaowner.h" #include "llviewermedia.h" #include "llviewermedia_streamingaudio.h" @@ -61,18 +62,18 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url) if (!mMediaPlugin) // lazy-init the underlying media plugin { mMediaPlugin = initializeMedia("audio/mpeg"); // assumes that whatever media implementation supports mp3 also supports vorbis. - llinfos << "mMediaPlugin is now " << mMediaPlugin << llendl; + llinfos << "steaming audio mMediaPlugin is now " << mMediaPlugin << llendl; } if(!mMediaPlugin) return; - + if (!url.empty()) { llinfos << "Starting internet stream: " << url << llendl; mURL = url; mMediaPlugin->loadURI ( url ); mMediaPlugin->start(); - llinfos << "Playing....." << llendl; + llinfos << "Playing stream..." << llendl; } else { llinfos << "setting stream to NULL"<< llendl; mURL.clear(); @@ -82,6 +83,7 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url) void LLStreamingAudio_MediaPlugins::stop() { + llinfos << "Stopping internet stream." << llendl; if(mMediaPlugin) { mMediaPlugin->stop(); @@ -97,10 +99,12 @@ void LLStreamingAudio_MediaPlugins::pause(int pause) if(pause) { + llinfos << "Pausing internet stream." << llendl; mMediaPlugin->pause(); } else { + llinfos << "Unpausing internet stream." << llendl; mMediaPlugin->start(); } } @@ -114,20 +118,21 @@ void LLStreamingAudio_MediaPlugins::update() int LLStreamingAudio_MediaPlugins::isPlaying() { if (!mMediaPlugin) - return 0; + return 0; // stopped - // *TODO: can probably do better than this - if (mMediaPlugin->isPluginRunning()) - { - return 1; // Active and playing - } + LLPluginClassMediaOwner::EMediaStatus status = + mMediaPlugin->getStatus(); - if (mMediaPlugin->isPluginExited()) + switch (status) { + case LLPluginClassMediaOwner::MEDIA_LOADING: // but not MEDIA_LOADED + case LLPluginClassMediaOwner::MEDIA_PLAYING: + return 1; // Active and playing + case LLPluginClassMediaOwner::MEDIA_PAUSED: + return 2; // paused + default: return 0; // stopped } - - return 2; // paused } void LLStreamingAudio_MediaPlugins::setGain(F32 vol) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 23bcca9603..2a9c738c97 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6479,21 +6479,27 @@ void menu_toggle_attached_particles(void* user_data) LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } -class LLAdvancedHandleAttchedLightParticles: public view_listener_t +class LLAdvancedHandleAttachedLightParticles: public view_listener_t { bool handleEvent(const LLSD& userdata) { std::string control_name = userdata.asString(); + + // toggle the control + gSavedSettings.setBOOL(control_name, + !gSavedSettings.getBOOL(control_name)); + + // update internal flags if (control_name == "RenderAttachedLights") -{ + { menu_toggle_attached_lights(NULL); -} + } else if (control_name == "RenderAttachedParticles") -{ + { menu_toggle_attached_particles(NULL); -} + } return true; -} + } }; class LLSomethingSelected : public view_listener_t @@ -7423,12 +7429,17 @@ class LLEditTakeOff : public view_listener_t { std::string clothing = userdata.asString(); if (clothing == "all") - LLAgentWearables::userRemoveAllClothes(); + LLWearableBridge::removeAllClothesFromAvatar(); else { EWearableType type = LLWearableDictionary::typeNameToType(clothing); if (type >= WT_SHAPE && type < WT_COUNT) - LLAgentWearables::userRemoveWearable(type); + { + // MULTI-WEARABLES + LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,0)); + LLWearableBridge::removeItemFromAvatar(item); + } + } return true; } @@ -7758,7 +7769,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest"); view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest"); view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest"); - view_listener_t::addMenu(new LLAdvancedHandleAttchedLightParticles(), "Advanced.HandleAttchedLightParticles"); + view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); #ifdef TOGGLE_HACKED_GODLIKE_VIEWER diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6a31bbfa1e..87045d2abf 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -906,6 +906,18 @@ void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& f LLFloaterReg::showInstance("preview_texture", LLSD(item_id), take_focus); break; } + case LLAssetType::AT_ANIMATION: + LLFloaterReg::showInstance("preview_anim", LLSD(item_id), take_focus); + break; + case LLAssetType::AT_GESTURE: + LLFloaterReg::showInstance("preview_gesture", LLSD(item_id), take_focus); + break; + case LLAssetType::AT_SCRIPT: + LLFloaterReg::showInstance("preview_script", LLSD(item_id), take_focus); + break; + case LLAssetType::AT_SOUND: + LLFloaterReg::showInstance("preview_sound", LLSD(item_id), take_focus); + break; default: break; } @@ -1146,9 +1158,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& default: LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; break; - } // end switch (mIM) - - // Show falls through to accept. + } + break; + // end switch (mIM) case IOR_ACCEPT: msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); @@ -1837,7 +1849,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // This is a block, modeless dialog. //*TODO: Translate args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessage", args); + LLNotificationsUtil::add("SystemMessageTip", args); } break; case IM_GROUP_NOTICE: @@ -2514,14 +2526,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string prefix = mesg.substr(0, 4); if (prefix == "/me " || prefix == "/me'") { -// chat.mText = from_name; -// chat.mText += mesg.substr(3); ircstyle = TRUE; } -// else -// { - chat.mText = mesg; -// } + chat.mText = mesg; // Look for the start of typing so we can put "..." in the bubbles. if (CHAT_TYPE_START == chat.mChatType) diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 69d2458217..993853b9a6 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -446,6 +446,17 @@ void LLVoiceChannel::resume() } } +boost::signals2::connection LLVoiceChannel::setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front) +{ + if (at_front) + { + return sCurrentVoiceChannelChangedSignal.connect(cb, boost::signals2::at_front); + } + else + { + return sCurrentVoiceChannelChangedSignal.connect(cb); + } +} // // LLVoiceChannelGroup diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 77801142cb..cb86671305 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -64,7 +64,7 @@ public: typedef boost::function<void(const LLUUID& session_id)> channel_changed_callback_t; typedef boost::signals2::signal<void(const LLUUID& session_id)> channel_changed_signal_t; static channel_changed_signal_t sCurrentVoiceChannelChangedSignal; - static boost::signals2::connection setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb) { return sCurrentVoiceChannelChangedSignal.connect(cb); } + static boost::signals2::connection setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front = false); LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index cfa1f05ec0..c2d26a1971 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -4443,6 +4443,33 @@ void LLVoiceClient::participantUpdatedEvent( participant->mPower = 0.0f; } participant->mVolume = volume; + + + // *HACH: mantipov: added while working on EXT-3544 + /* + Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE + LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER. + + participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted + Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug. + Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates. + + But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post() + voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager + and event is not fired. + + So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it + in LLCallFloater::draw() + */ + LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel(); + if (voice_cnl) + { + LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID()); + if (speaker_manager) + { + speaker_manager->update(true); + } + } } else { diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index f8bb7336db..7866f735c5 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -38,10 +38,12 @@ // Library includes #include "llwindow.h" // spawnWebBrowser() +#include "llagent.h" #include "llappviewer.h" #include "llfloatermediabrowser.h" #include "llfloaterreg.h" #include "lllogininstance.h" +#include "llparcel.h" #include "llsd.h" #include "lltoastalertpanel.h" #include "llui.h" @@ -49,6 +51,8 @@ #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewernetwork.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "llviewerwindow.h" class URLLoader : public LLToastAlertPanel::URLLoader @@ -144,7 +148,27 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, substitution["LANGUAGE"] = LLUI::getLanguage(); substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel(); substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + substitution["SESSION_ID"] = gAgent.getSessionID(); + // find the region ID + LLUUID region_id; + LLViewerRegion *region = gAgent.getRegion(); + if (region) + { + region_id = region->getRegionID(); + } + substitution["REGION_ID"] = region_id; + + // find the parcel ID + LLUUID parcel_id; + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + parcel_id = parcel->getID(); + } + substitution["PARCEL_ID"] = parcel_id; + + // expand all of the substitution strings and escape the url std::string expanded_url = url; LLStringUtil::format(expanded_url, substitution); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index e6857ea780..1940d65ae4 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -334,7 +334,6 @@ void LLWorldMapView::draw() gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setColorMask(true, true); -#if 1 // Draw the image tiles drawMipmap(width, height); gGL.flush(); @@ -452,7 +451,7 @@ void LLWorldMapView::draw() // Draw the region name in the lower left corner if (sMapScale >= DRAW_TEXT_THRESHOLD) { - LLFontGL* font = LLFontGL::getFontSansSerifSmall(); + LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Small", LLFontGL::BOLD)); std::string mesg; if (info->isDown()) { @@ -468,14 +467,13 @@ void LLWorldMapView::draw() mesg, 0, llfloor(left + 3), llfloor(bottom + 2), LLColor4::white, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } } } - #endif - #if 1 + // Draw background rectangle LLGLSUIDefault gls_ui; { @@ -566,7 +564,7 @@ void LLWorldMapView::draw() drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("Loading"), ""); } } - #endif + // turn off the scissor LLGLDisable no_scissor(GL_SCISSOR_TEST); diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index 9897f40c4e..1cdccd2baa 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -186,9 +186,8 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level) { // Get the grid coordinates -// std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/%d/%05d/%05d/map-%d-%d-%d-objects.jpg", std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/map-%d-%d-%d-objects.jpg", - level, grid_x, grid_y, level, grid_x, grid_y); + level, grid_x, grid_y); // DO NOT COMMIT!! DEBUG ONLY!!! // Use a local jpeg for every tile to test map speed without S3 access diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 706245a479..cb511c2f0b 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -102,6 +102,24 @@ name="AvatarNameColor" reference="White" /> <color + name="AvatarListItemIconDefaultColor" + reference="White" /> + <color + name="AvatarListItemIconOnlineColor" + reference="White" /> + <color + name="AvatarListItemIconOfflineColor" + value="0.5 0.5 0.5 0.5" /> + <color + name="AvatarListItemIconVoiceInvitedColor" + reference="AvatarListItemIconOfflineColor" /> + <color + name="AvatarListItemIconVoiceJoinedColor" + reference="AvatarListItemIconOnlineColor" /> + <color + name="AvatarListItemIconVoiceLeftColor" + reference="AvatarListItemIconOfflineColor" /> + <color name="BackgroundChatColor" reference="DkGray_66" /> <color diff --git a/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg b/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg Binary files differnew file mode 100644 index 0000000000..3bb7f7183c --- /dev/null +++ b/indra/newview/skins/default/textures/icons/avaline_default_icon.jpg diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b8de6672ec..857936fbae 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -70,6 +70,8 @@ with the same filename but different name <texture name="Audio_Over" file_name="icons/Audio_Over.png" preload="false" /> <texture name="Audio_Press" file_name="icons/Audio_Press.png" preload="false" /> + <texture name="Avaline_Icon" file_name="icons/avaline_default_icon.jpg" preload="true" /> + <texture name="BackArrow_Disabled" file_name="icons/BackArrow_Disabled.png" preload="false" /> <texture name="BackArrow_Off" file_name="icons/BackArrow_Off.png" preload="false" /> <texture name="BackArrow_Press" file_name="icons/BackArrow_Press.png" preload="false" /> 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 81c54ae55e..b9ce11600f 100644 --- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml +++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml @@ -11,6 +11,10 @@ title="UNKNOWN PERSON IS CALLING" width="410"> <floater.string + name="lifetime"> + 5 + </floater.string> + <floater.string name="localchat"> Nearby Voice Chat </floater.string> diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml index fb8893678d..920f0c909a 100644 --- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml @@ -16,8 +16,10 @@ can_dock="true" bevel_style="in" height="300" + min_width="150" layout="topleft" name="nearby_chat" + help_topic="nearby_chat" save_rect="true" title="NEARBY CHAT" save_dock_state="true" diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml index c6bc093c6c..104ac2143f 100644 --- a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml +++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml @@ -11,6 +11,10 @@ title="CALLING" width="410"> <floater.string + name="lifetime"> + 5 + </floater.string> + <floater.string name="localchat"> Nearby Voice Chat </floater.string> diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index ec54522d3e..a36a1b591b 100644 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -9,6 +9,7 @@ name="Snapshot" help_topic="snapshot" save_rect="true" + save_visibility="true" title="SNAPSHOT PREVIEW" width="215"> <floater.string diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index 169a0ea676..8904d4f49c 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -480,7 +480,10 @@ name="location" select_on_focus="true" tool_tip="Type the name of a region" - width="152" /> + width="152"> + <search_editor.commit_callback + function="WMap.Location" /> + </search_editor> <button follows="top|right" height="23" diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index c849188699..9b3948b29b 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -104,6 +104,9 @@ <on_click function="Places.LandmarksGear.Folding.Action" parameter="expand_all" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="expand_all" /> </menu_item_call> <menu_item_call label="Collapse all folders" @@ -112,6 +115,9 @@ <on_click function="Places.LandmarksGear.Folding.Action" parameter="collapse_all" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="collapse_all" /> </menu_item_call> <menu_item_check label="Sort by Date" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8f1799688b..0640ae21de 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2481,30 +2481,30 @@ name="Debug Pipeline"> <menu_item_check.on_check function="CheckControl" - parameter="RenderDebugGL" /> + parameter="RenderDebugPipeline" /> <menu_item_check.on_click function="ToggleControl" - parameter="RenderDebugGL" /> + parameter="RenderDebugPipeline" /> </menu_item_check> <menu_item_check label="Fast Alpha" name="Fast Alpha"> <menu_item_check.on_check function="CheckControl" - parameter="RenderDebugGL" /> + parameter="RenderFastAlpha" /> <menu_item_check.on_click function="ToggleControl" - parameter="RenderDebugGL" /> + parameter="RenderFastAlpha" /> </menu_item_check> <menu_item_check label="Animation Textures" name="Animation Textures"> <menu_item_check.on_check function="CheckControl" - parameter="RenderDebugGL" /> + parameter="AnimateTextures" /> <menu_item_check.on_click function="ToggleControl" - parameter="RenderDebugGL" /> + parameter="AnimateTextures" /> </menu_item_check> <menu_item_check label="Disable Textures" @@ -2555,7 +2555,7 @@ function="CheckControl" parameter="RenderAttachedLights" /> <menu_item_check.on_click - function="Advanced.HandleAttchedLightParticles" + function="Advanced.HandleAttachedLightParticles" parameter="RenderAttachedLights" /> </menu_item_check> <menu_item_check @@ -2565,7 +2565,7 @@ function="CheckControl" parameter="RenderAttachedParticles" /> <menu_item_check.on_click - function="Advanced.HandleAttchedLightParticles" + function="Advanced.HandleAttachedLightParticles" parameter="RenderAttachedParticles" /> </menu_item_check> <menu_item_check diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d4b712e048..9d3c31c4e6 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4498,14 +4498,14 @@ You don't have permission to copy this. <notification icon="notifytip.tga" name="InventoryAccepted" - type="offer"> + type="notifytip"> [NAME] received your inventory offer. </notification> <notification icon="notifytip.tga" name="InventoryDeclined" - type="offer"> + type="notifytip"> [NAME] declined your inventory offer. </notification> @@ -5022,9 +5022,9 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you [O [ITEM_SLURL] <form name="form"> <button - index="0" - name="Keep" - text="Keep"/> + index="4" + name="Show" + text="Show"/> <button index="1" name="Discard" @@ -5106,7 +5106,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you [O <notification icon="notify.tga" name="OfferFriendship" - type="offer"> + type="alertmodal"> [NAME] is offering friendship. [MESSAGE] diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 5ae808581d..00eba94f47 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -227,16 +227,20 @@ <button follows="left|right" height="23" + image_selected="PushButton_Selected_Press" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" left="0" label="" layout="topleft" name="snapshots" width="36" top="4" + is_toggle="true" image_overlay="Snapshot_Off" tool_tip="Take snapshot"> - <button.commit_callback - function="Floater.Toggle" + <button.init_callback + function="Button.SetFloaterToggle" parameter="snapshot" /> </button> </layout_panel> @@ -248,7 +252,7 @@ top="0" name="chiclet_list_panel" width="189" - min_width="180" + min_width="100" user_resize="false" auto_resize="true"> <!--*NOTE: min_width of the chiclet_panel (chiclet_list) must be the same @@ -259,7 +263,7 @@ as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly. height="23" layout="topleft" left="1" - min_width="180" + min_width="110" name="chiclet_list" top="6" chiclet_padding="4" diff --git a/indra/newview/skins/default/xui/en/panel_chat_header.xml b/indra/newview/skins/default/xui/en/panel_chat_header.xml index 859822dd81..39c4923f12 100644 --- a/indra/newview/skins/default/xui/en/panel_chat_header.xml +++ b/indra/newview/skins/default/xui/en/panel_chat_header.xml @@ -28,7 +28,7 @@ height="12" layout="topleft" left_pad="5" - right="-60" + right="-120" name="user_name" text_color="white" bg_readonly_color="black" @@ -46,5 +46,5 @@ right="-5" top="8" value="23:30" - width="50" /> + width="110" /> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml index b5760e977f..1fbf7abda9 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_classified.xml @@ -103,6 +103,7 @@ top_pad="2" max_length="63" name="classified_name" + prevalidate_callback="ascii" text_color="black" width="290" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml index c581ab9f2b..67a4edbf32 100644 --- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml @@ -228,6 +228,16 @@ top_pad="10" value="Title:" width="290" /> + <text + follows="left|top" + height="22" + layout="topleft" + left="0" + name="title_value" + text_color="white" + top_pad="5" + use_ellipses="true" + width="290" /> <line_editor follows="left|top|right" height="22" @@ -237,7 +247,7 @@ name="title_editor" prevalidate_callback="ascii" text_readonly_color="white" - top_pad="5" + top_delta="0" width="290" /> <text follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml index 1f211c0fed..c899dcb750 100644 --- a/indra/newview/skins/default/xui/en/panel_landmarks.xml +++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml @@ -23,7 +23,7 @@ layout="topleft" name="tab_favorites" title="Favorites bar"> - <inventory_subtree_panel + <places_inventory_panel allow_multi_select="true" border="true" bottom="0" @@ -39,7 +39,7 @@ layout="topleft" name="tab_landmarks" title="Landmarks"> - <inventory_subtree_panel + <places_inventory_panel allow_multi_select="true" border="true" bottom="0" @@ -55,7 +55,7 @@ layout="topleft" name="tab_inventory" title="My Inventory"> - <inventory_subtree_panel + <places_inventory_panel allow_multi_select="true" border="true" bottom="0" @@ -71,7 +71,7 @@ layout="topleft" name="tab_library" title="Library"> - <inventory_subtree_panel + <places_inventory_panel allow_multi_select="true" border="true" bottom="0" diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 57b090e5b4..3578c4326d 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -80,16 +80,6 @@ name="volume_btn" tool_tip="Global Volume Control" width="16" /> - <panel - class="panel_volume_pulldown" - follows="all" - height="533" - layout="topleft" - left="0" - name="volume_pulldown" - top="5" - visible="false" - width="313" /> <text enabled="true" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index acdf3d1bf7..447901f984 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2904,13 +2904,13 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="joined_call">Joined the voice call</string> <string name="ringing-im"> - Joining Voice Chat... + Joining voice call... </string> <string name="connected-im"> - Connected, click End Call to hang up + Connected, click Leave Call to hang up </string> <string name="hang_up-im"> - Left Voice Chat + Left voice call </string> <string name="answering-im"> Connecting... @@ -2990,6 +2990,13 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="mute"> Error while moderating. </string> + <!--Some times string name is getting from the body of server response. + For ex.: from gIMMgr::showSessionStartError in the LLViewerChatterBoxSessionStartReply::post. + In case of the EXT-3459 issue 'removed' is passed into the gIMMgr::showSessionStartError as a string name. + So, let add string with name="removed" with the same value as "removed_from_group" --> + <string name="removed"> + You have been removed from the group. + </string> <string name="removed_from_group"> You have been removed from the group. </string> diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml new file mode 100644 index 0000000000..7cb973f4c8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_im_adhoc + font="SansSerif" + height="25" + name="im_adhoc_chiclet" + show_speaker="false" + width="25"> + <chiclet_im_adhoc.speaker + auto_update="true" + draw_border="false" + height="25" + left="25" + name="speaker" + visible="false" + width="20"/> + <chiclet_im_adhoc.avatar_icon + follows="left|top|bottom" + height="22" + mouse_opaque="true" + name="adhoc_icon" + width="22"/> + <chiclet_im_adhoc.unread_notifications + font="SansSerif" + font_halign="center" + height="25" + left="25" + mouse_opaque="false" + name="unread" + text_color="white" + v_pad="5" + visible="false" + width="20"/> + <chiclet_im_adhoc.new_message_icon + bottom="12" + height="13" + image_name="Unread_IM" + left="12" + name="new_message_icon" + visible="false" + width="13" /> +</chiclet_im_adhoc>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml new file mode 100644 index 0000000000..a9b567225e --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_im_group + font="SansSerif" + height="25" + name="im_group_chiclet" + show_speaker="false" + width="25"> + <chiclet_im_group.speaker + auto_update="true" + draw_border="false" + height="25" + left="25" + name="speaker" + visible="false" + width="20"/> + <chiclet_im_group.group_icon + default_icon="Generic_Group" + follows="left|top|bottom" + height="22" + mouse_opaque="true" + name="group_icon" + width="22"/> + <chiclet_im_group.unread_notifications + height="25" + font="SansSerif" + font_halign="center" + left="25" + mouse_opaque="false" + name="unread" + text_color="white" + v_pad="5" + visible="false" + width="20"/> + <chiclet_im_group.new_message_icon + bottom="12" + height="13" + image_name="Unread_IM" + left="12" + name="new_message_icon" + visible="false" + width="13" /> +</chiclet_im_group>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml new file mode 100644 index 0000000000..9283594a4c --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_im_p2p + font="SansSerif" + height="25" + name="im_p2p_chiclet" + show_speaker="false" + width="25"> + <chiclet_im_p2p.speaker + auto_update="true" + draw_border="false" + height="25" + left="25" + name="speaker" + visible="false" + width="20"/> + <chiclet_im_p2p.avatar_icon + follows="left|top|bottom" + height="22" + mouse_opaque="true" + name="avatar_icon" + width="22"/> + <chiclet_im_p2p.unread_notifications + height="25" + font="SansSerif" + font_halign="center" + left="25" + mouse_opaque="false" + name="unread" + text_color="white" + v_pad="5" + visible="false" + width="20"/> + <chiclet_im_p2p.new_message_icon + bottom="12" + height="13" + image_name="Unread_IM" + left="12" + name="new_message_icon" + visible="false" + width="13" /> +</chiclet_im_p2p>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml new file mode 100644 index 0000000000..5a22563758 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_offer + font="SansSerif" + height="25" + name="offer_chiclet" + width="25"> + <chiclet_offer.icon + default_icon="Generic_Object_Small" + follows="all" + height="22" + mouse_opaque="false" + name="chiclet_icon" + width="22"/> + <chiclet_offer.new_message_icon + bottom="12" + height="13" + image_name="Unread_IM" + left="12" + name="new_message_icon" + visible="false" + width="13" /> +</chiclet_offer>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_panel.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_panel.xml new file mode 100644 index 0000000000..f3207ddeae --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_panel.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_panel + name="chiclet_panel" + chiclet_padding="3" + scrolling_offset="40" + scroll_button_hpad="5" + scroll_ratio="10" + min_width="180" + />
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml index e5af961a56..05a23b95f9 100644 --- a/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml @@ -1,10 +1,22 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<chiclet_script
- name="script_chiclet"
- font="SansSerif">
- <icon
- name="chiclet_icon"
- follows="all"
- mouse_opaque="false"
- image_name="Generic_Object_Small" />
-</expandable_text>
\ No newline at end of file +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chiclet_script + font="SansSerif" + height="25" + name="script_chiclet" + width="25"> + <chiclet_script.icon + follows="all" + height="22" + image_name="Generic_Object_Small" + mouse_opaque="false" + name="chiclet_icon" + width="22"/> + <chiclet_script.new_message_icon + bottom="12" + height="13" + image_name="Unread_IM" + left="12" + name="new_message_icon" + visible="false" + width="13" /> +</chiclet_script>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/output_monitor.xml b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml index 21b957d089..9d71ceca2f 100644 --- a/indra/newview/skins/default/xui/en/widgets/output_monitor.xml +++ b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml @@ -1,9 +1,13 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <output_monitor + draw_border="true" + follows="top|left" image_mute="Parcel_VoiceNo_Light" image_off="VoicePTT_Off" image_on="VoicePTT_On" image_level_1="VoicePTT_Lvl1" image_level_2="VoicePTT_Lvl2" image_level_3="VoicePTT_Lvl3" + mouse_opaque="false" + name="output_monitor" /> |