diff options
Diffstat (limited to 'indra')
70 files changed, 1257 insertions, 492 deletions
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 9a281926bf..bfa2c34c12 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -31,7 +31,6 @@ set(llaudio_SOURCE_FILES llaudioengine.cpp lllistener.cpp llaudiodecodemgr.cpp - llvorbisdecode.cpp llvorbisencode.cpp ) @@ -41,7 +40,6 @@ set(llaudio_HEADER_FILES llaudioengine.h lllistener.h llaudiodecodemgr.h - llvorbisdecode.h llvorbisencode.h llwindgen.h ) diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index ae959eaa81..6bbaad9cef 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -33,7 +33,6 @@ #include "llaudiodecodemgr.h" -#include "llvorbisdecode.h" #include "llaudioengine.h" #include "lllfsthread.h" #include "llvfile.h" diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 8de3a8a96f..ddfb0f8534 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -484,6 +484,8 @@ void LLFlatListView::rearrangeItems() void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) { if (!item_pair) return; + + setFocus(TRUE); bool select_item = !isSelected(item_pair); @@ -554,12 +556,21 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) break; } - if ( key == KEY_UP || key == KEY_DOWN ) + if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() ) { - LLRect selcted_rect = getLastSelectedItemRect().stretch(1); - LLRect visible_rect = getVisibleContentRect(); - if ( !visible_rect.contains (selcted_rect) ) - scrollToShowRect(selcted_rect); + LLRect visible_rc = getVisibleContentRect(); + LLRect selected_rc = getLastSelectedItemRect(); + + if ( !visible_rc.contains (selected_rc) ) + { + // But scroll in Items panel coordinates + scrollToShowRect(selected_rc); + } + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(selected_rc, &screen_rc); + notifyParent(LLSD().insert("scrollToShowRect",screen_rc.getValue())); handled = TRUE; } @@ -645,8 +656,6 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) onCommit(); } - setFocus(TRUE); - // Stretch selected items rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getSelectedItemsRect().stretch(-1)); diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index a7cf9be277..0c46edf300 100644 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -144,9 +144,10 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask) if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView ) { // undock floater when user resize it - if (((LLFloater*)getParent())->isDocked()) + LLFloater* parent = dynamic_cast<LLFloater*>( getParent()); + if (parent && parent->isDocked()) { - ((LLFloater*)getParent())->setDocked(false, false); + parent->setDocked( false, false); } // Resize the parent diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 5e17372fe9..d91b58b4ea 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -111,7 +111,8 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p) LLView::addChild( mBorder ); mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - mInnerRect.stretch( -mBorder->getBorderWidth() ); + if ( mBorder->getVisible() ) + mInnerRect.stretch( -mBorder->getBorderWidth() ); LLRect vertical_scroll_rect = mInnerRect; vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size; @@ -189,7 +190,8 @@ void LLScrollContainer::reshape(S32 width, S32 height, LLUICtrl::reshape( width, height, called_from_parent ); mInnerRect = getLocalRect(); - mInnerRect.stretch( -mBorder->getBorderWidth() ); + if ( mBorder->getVisible() ) + mInnerRect.stretch( -mBorder->getBorderWidth() ); if (mScrolledView) { diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 959313a5b6..d7228c78bd 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -228,7 +228,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p) { LLButton::Params p_button; p_button.name(std::string("play_media")); - p_button.label(""); // provid label but set to empty so name does not overwrite it -angela + p_button.label(""); // provide label but set to empty so name does not overwrite it -angela TOOLTIP_PLAYBUTTON_SIZE = 16; LLRect button_rect; button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e632cbaaf2..91f43137c5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -90,6 +90,7 @@ set(viewer_SOURCE_FILES llbox.cpp llbreadcrumbview.cpp llcallbacklist.cpp + llcallfloater.cpp llcallingcard.cpp llcapabilitylistener.cpp llcaphttpsender.cpp @@ -185,7 +186,7 @@ set(viewer_SOURCE_FILES llfloatermediasettings.cpp llfloatermemleak.cpp llfloaternamedesc.cpp - llfloaternearbymedia.cpp + llfloaternearbymedia.cpp llfloaternotificationsconsole.cpp llfloateropenobject.cpp llfloaterparcel.cpp @@ -212,6 +213,7 @@ set(viewer_SOURCE_FILES llfloaterurldisplay.cpp llfloaterurlentry.cpp llfloatervoicedevicesettings.cpp + llfloatervolumepulldown.cpp llfloaterwater.cpp llfloaterwhitelistentry.cpp llfloaterwindlight.cpp @@ -291,6 +293,7 @@ set(viewer_SOURCE_FILES llnetmap.cpp llnotificationalerthandler.cpp llnotificationgrouphandler.cpp + llnotificationhandlerutil.cpp llnotificationmanager.cpp llnotificationofferhandler.cpp llnotificationscripthandler.cpp @@ -588,6 +591,7 @@ set(viewer_HEADER_FILES llbox.h llbreadcrumbview.h llcallbacklist.h + llcallfloater.h llcallingcard.h llcapabilitylistener.h llcapabilityprovider.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f196ebbf93..eb08707b61 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -907,6 +907,7 @@ static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache"); static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode"); static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread"); +static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread"); static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads"); static LLFastTimer::DeclareTimer FTM_IDLE("Idle"); static LLFastTimer::DeclareTimer FTM_PUMP("Pump"); @@ -1123,6 +1124,10 @@ bool LLAppViewer::mainLoop() LLFastTimer ftm(FTM_VFS); io_pending += LLVFSThread::updateClass(1); } + { + LLFastTimer ftm(FTM_LFS); + io_pending += LLLFSThread::updateClass(1); + } if (io_pending > 1000) { diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index 327d80ba34..8f3eba98a6 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -234,6 +234,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value) // Check if cache already contains image_id for that avatar if (!updateFromCache()) { + LLIconCtrl::setValue(mDefaultIconName); app->addObserver(mAvatarId, this); app->sendAvatarPropertiesRequest(mAvatarId); } diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index bb03f47f46..202fbdebd4 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -153,6 +153,13 @@ void LLAvatarList::draw() } } +//virtual +void LLAvatarList::clear() +{ + getIDs().clear(); + setDirty(true); +} + void LLAvatarList::setNameFilter(const std::string& filter) { if (mNameFilter != filter) @@ -363,37 +370,6 @@ void LLAvatarList::computeDifference( vadded.erase(it, vadded.end()); } -static std::string format_secs(S32 secs) -{ - // *TODO: reinventing the wheel? - // *TODO: i18n - static const int LL_AL_MIN = 60; - static const int LL_AL_HOUR = LL_AL_MIN * 60; - static const int LL_AL_DAY = LL_AL_HOUR * 24; - static const int LL_AL_WEEK = LL_AL_DAY * 7; - static const int LL_AL_MONTH = LL_AL_DAY * 31; - static const int LL_AL_YEAR = LL_AL_DAY * 365; - - std::string s; - - if (secs >= LL_AL_YEAR) - s = llformat("%dy", secs / LL_AL_YEAR); - else if (secs >= LL_AL_MONTH) - s = llformat("%dmon", secs / LL_AL_MONTH); - else if (secs >= LL_AL_WEEK) - s = llformat("%dw", secs / LL_AL_WEEK); - else if (secs >= LL_AL_DAY) - s = llformat("%dd", secs / LL_AL_DAY); - else if (secs >= LL_AL_HOUR) - s = llformat("%dh", secs / LL_AL_HOUR); - else if (secs >= LL_AL_MIN) - s = llformat("%dm", secs / LL_AL_MIN); - else - s = llformat("%ds", secs); - - return s; -} - // Refresh shown time of our last interaction with all listed avatars. void LLAvatarList::updateLastInteractionTimes() { @@ -407,7 +383,7 @@ void LLAvatarList::updateLastInteractionTimes() LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it); S32 secs_since = now - (S32) LLRecentPeople::instance().getDate(item->getAvatarId()).secondsSinceEpoch(); if (secs_since >= 0) - item->setLastInteractionTime(format_secs(secs_since)); + item->setLastInteractionTime(secs_since); } } diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 490f93e501..9058fec540 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -70,6 +70,8 @@ public: virtual void draw(); // from LLView + virtual void clear(); + void setNameFilter(const std::string& filter); void setDirty(bool val = true) { mDirty = val; } uuid_vector_t& getIDs() { return mIDs; } diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index c670a65bcc..efc9538fa6 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -198,9 +198,9 @@ void LLAvatarListItem::showLastInteractionTime(bool show) mAvatarName->setRect(name_rect); } -void LLAvatarListItem::setLastInteractionTime(const std::string& val) +void LLAvatarListItem::setLastInteractionTime(U32 secs_since) { - mLastInteractionTime->setValue(val); + mLastInteractionTime->setValue(formatSeconds(secs_since)); } void LLAvatarListItem::setShowInfoBtn(bool show) @@ -326,3 +326,51 @@ void LLAvatarListItem::reshapeAvatarName() mAvatarName->reshape(width, height); } + +// Convert given number of seconds to a string like "23 minutes", "15 hours" or "3 years", +// taking i18n into account. The format string to use is taken from the panel XML. +std::string LLAvatarListItem::formatSeconds(U32 secs) +{ + static const U32 LL_ALI_MIN = 60; + static const U32 LL_ALI_HOUR = LL_ALI_MIN * 60; + static const U32 LL_ALI_DAY = LL_ALI_HOUR * 24; + static const U32 LL_ALI_WEEK = LL_ALI_DAY * 7; + static const U32 LL_ALI_MONTH = LL_ALI_DAY * 30; + static const U32 LL_ALI_YEAR = LL_ALI_DAY * 365; + + std::string fmt; + U32 count = 0; + + if (secs >= LL_ALI_YEAR) + { + fmt = "FormatYears"; count = secs / LL_ALI_YEAR; + } + else if (secs >= LL_ALI_MONTH) + { + fmt = "FormatMonths"; count = secs / LL_ALI_MONTH; + } + else if (secs >= LL_ALI_WEEK) + { + fmt = "FormatWeeks"; count = secs / LL_ALI_WEEK; + } + else if (secs >= LL_ALI_DAY) + { + fmt = "FormatDays"; count = secs / LL_ALI_DAY; + } + else if (secs >= LL_ALI_HOUR) + { + fmt = "FormatHours"; count = secs / LL_ALI_HOUR; + } + else if (secs >= LL_ALI_MIN) + { + fmt = "FormatMinutes"; count = secs / LL_ALI_MIN; + } + else + { + fmt = "FormatSeconds"; count = secs; + } + + LLStringUtil::format_map_t args; + args["[COUNT]"] = llformat("%u", count); + return getString(fmt, args); +} diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 9d48101a44..341f5a6bcf 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -63,7 +63,7 @@ public: void setOnline(bool online); void setName(const std::string& name); void setAvatarId(const LLUUID& id, bool ignore_status_changes = false); - void setLastInteractionTime(const std::string& val); + void setLastInteractionTime(U32 secs_since); //Show/hide profile/info btn, translating speaker indicator and avatar name coordinates accordingly void setShowProfileBtn(bool show); void setShowInfoBtn(bool show); @@ -94,6 +94,8 @@ private: void onNameCache(const std::string& first_name, const std::string& last_name); + std::string formatSeconds(U32 secs); + LLAvatarIconCtrl* mAvatarIcon; LLTextBox* mAvatarName; LLTextBox* mLastInteractionTime; diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp new file mode 100644 index 0000000000..b41f962ffa --- /dev/null +++ b/indra/newview/llcallfloater.cpp @@ -0,0 +1,138 @@ +/** + * @file llcallfloater.cpp + * @author Mike Antipov + * @brief Voice Control Panel in a Voice Chats (P2P, Group, Nearby...). + * + * $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 "llcallfloater.h" + +#include "llavatarlist.h" +#include "llbottomtray.h" +#include "llparticipantlist.h" +#include "llspeakers.h" + + +LLCallFloater::LLCallFloater(const LLSD& key) +: LLDockableFloater(NULL, key) +, mSpeakerManager(NULL) +, mPaticipants(NULL) +, mAvatarList(NULL) +{ + +} + +LLCallFloater::~LLCallFloater() +{ + delete mPaticipants; + mPaticipants = NULL; +} + +// virtual +BOOL LLCallFloater::postBuild() +{ + LLDockableFloater::postBuild(); + mAvatarList = getChild<LLAvatarList>("speakers_list"); + + + LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("speak_panel"); + + setDockControl(new LLDockControl( + anchor_panel, this, + getDockTongue(), LLDockControl::TOP)); + + // update list for current session + updateSession(); + + // subscribe to to be notified Voice Channel is changed + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::onCurrentChannelChanged, this, _1)); + return TRUE; +} + +// virtual +void LLCallFloater::onOpen(const LLSD& /*key*/) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// PRIVATE SECTION +////////////////////////////////////////////////////////////////////////// +void LLCallFloater::updateSession() +{ + LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel(); + if (voice_channel) + { + lldebugs << "Current voice channel: " << voice_channel->getSessionID() << llendl; + + if (mSpeakerManager && voice_channel->getSessionID() == mSpeakerManager->getSessionID()) + { + lldebugs << "Speaker manager is already set for session: " << voice_channel->getSessionID() << llendl; + return; + } + else + { + mSpeakerManager = NULL; + } + } + + const LLUUID& session_id = voice_channel->getSessionID(); + lldebugs << "Set speaker manager for session: " << session_id << llendl; + + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (im_session) + { + mSpeakerManager = LLIMModel::getInstance()->getSpeakerManager(session_id); + } + + if (NULL == mSpeakerManager) + { + // by default let show nearby chat participants + mSpeakerManager = LLLocalSpeakerMgr::getInstance(); + lldebugs << "Set DEFAULT speaker manager" << llendl; + } + + refreshPartisipantList(); +} + +void LLCallFloater::refreshPartisipantList() +{ + delete mPaticipants; + mAvatarList->clear(); + + bool do_not_use_context_menu_in_local_chat = LLLocalSpeakerMgr::getInstance() != mSpeakerManager; + mPaticipants = new LLParticipantList(mSpeakerManager, mAvatarList, do_not_use_context_menu_in_local_chat); +} + +void LLCallFloater::onCurrentChannelChanged(const LLUUID& /*session_id*/) +{ + updateSession(); +} +//EOF diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h new file mode 100644 index 0000000000..bfaa1075c4 --- /dev/null +++ b/indra/newview/llcallfloater.h @@ -0,0 +1,86 @@ +/** + * @file llcallfloater.h + * @author Mike Antipov + * @brief Voice Control Panel in a Voice Chats (P2P, Group, Nearby...). + * + * $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_LLCALLFLOATER_H +#define LL_LLCALLFLOATER_H + +#include "lldockablefloater.h" + +class LLAvatarList; +class LLParticipantList; +class LLSpeakerMgr; + +/** + * The Voice Control Panel is an ambient window summoned by clicking the flyout chevron on the Speak button. + * It can be torn-off and freely positioned onscreen. + * + * When the Resident is engaged in Nearby Voice Chat, the Voice Control Panel provides control over + * the Resident's own microphone input volume, the audible volume of each of the other participants, + * the Resident's own Voice Morphing settings (if she has subscribed to enable the feature), and Voice Recording. + * + * When the Resident is engaged in Group Voice Chat, the Voice Control Panel also provides an + * 'End Call' button to allow the Resident to leave that voice channel. + */ +class LLCallFloater : public LLDockableFloater +{ +public: + LLCallFloater(const LLSD& key); + ~LLCallFloater(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + +private: + /** + * Updates mSpeakerManager and list according to current Voice Channel + * + * It compares mSpeakerManager & current Voice Channel session IDs. + * If they are different gets Speaker manager related to current channel and updates channel participant list. + */ + void updateSession(); + + /** + * Refreshes participant list according to current Voice Channel + */ + void refreshPartisipantList(); + void onCurrentChannelChanged(const LLUUID& session_id); + +private: + LLSpeakerMgr* mSpeakerManager; + LLParticipantList* mPaticipants; + LLAvatarList* mAvatarList; +}; + + +#endif //LL_LLCALLFLOATER_H + diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 476f1f41ac..714bd20ab8 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -633,20 +633,21 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) { if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^ new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS) { - std::string first, last; + std::string name; LLSD args; - if(gCacheName->getName(agent_id, first, last)) + if(gCacheName->getFullName(agent_id, name)) { - args["FIRST_NAME"] = first; - args["LAST_NAME"] = last; + args["NAME"] = name; } + LLSD payload; + payload["from_id"] = agent_id; if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights) { - LLNotificationsUtil::add("GrantedModifyRights",args); + LLNotificationsUtil::add("GrantedModifyRights",args, payload); } else { - LLNotificationsUtil::add("RevokedModifyRights",args); + LLNotificationsUtil::add("RevokedModifyRights",args, payload); } } (mBuddyInfo[agent_id])->setRightsFrom(new_rights); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 2c9b38b82a..caf9c08057 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -199,7 +199,7 @@ public: userName->setValue(SL); } - setTimeField(chat.mTimeStr); + setTimeField(chat); LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); @@ -267,11 +267,29 @@ protected: } private: - void setTimeField(const std::string& time_value) + std::string appendTime(const LLChat& chat)
+ {
+ time_t utc_time;
+ utc_time = time_corrected();
+ std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:["
+ +LLTrans::getString("TimeMin")+"] ";
+
+ LLSD substitution;
+
+ substitution["datetime"] = (S32) utc_time;
+ LLStringUtil::format (timeStr, substitution);
+
+ return timeStr;
+ }
+ + void setTimeField(const LLChat& chat) { LLTextBox* time_box = getChild<LLTextBox>("time_box"); LLRect rect_before = time_box->getRect(); + + std::string time_value = appendTime(chat); + time_box->setValue(time_value); // set necessary textbox width to fit all text @@ -386,7 +404,11 @@ void LLChatHistory::appendMessage(const LLChat& chat, const bool use_plain_text_ p.left_pad = mLeftWidgetPad; p.right_pad = mRightWidgetPad; - if (mLastFromName == chat.mFromName) + LLDate new_message_time = LLDate::now(); + + if (mLastFromName == chat.mFromName && + mLastMessageTime.notNull() && + (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0 ) { view = getSeparator(); p.top_pad = mTopSeparatorPad; @@ -414,6 +436,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const bool use_plain_text_ appendWidget(p, header_text, false); mLastFromName = chat.mFromName; + mLastMessageTime = new_message_time; } //Handle IRC styled /me messages. std::string prefix = chat.mText.substr(0, 4); diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index ef5839ff2f..d2cfa53d8b 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -114,6 +114,7 @@ class LLChatHistory : public LLTextEditor private: std::string mLastFromName; + LLDate mLastMessageTime; std::string mMessageHeaderFilename; std::string mMessageSeparatorFilename; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 8a6935b71b..efdaff3f6a 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -44,27 +44,12 @@ #include "llviewercontrol.h" #include "llagentdata.h" -/* -static const S32 BORDER_MARGIN = 2; -static const S32 PARENT_BORDER_MARGIN = 0; - -static const S32 HORIZONTAL_MULTIPLE = 8; -static const S32 VERTICAL_MULTIPLE = 16; -static const F32 MIN_AUTO_SCROLL_RATE = 120.f; -static const F32 MAX_AUTO_SCROLL_RATE = 500.f; -static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; - -#define MAX_CHAT_HISTORY 100 -*/ - -static const S32 msg_left_offset = 30; +static const S32 msg_left_offset = 10; static const S32 msg_right_offset = 10; -static const S32 msg_height_pad = 2; - -//static LLDefaultChildRegistry::Register<LLChatItemsContainerCtrl> t2("chat_items_container"); +static const S32 msg_height_pad = 5; //******************************************************************************************************************* -//LLChatItemCtrl +//LLNearbyChatToastPanel //******************************************************************************************************************* LLNearbyChatToastPanel* LLNearbyChatToastPanel::createInstance() @@ -79,22 +64,22 @@ void LLNearbyChatToastPanel::reshape (S32 width, S32 height, BOOL called_from_p { LLPanel::reshape(width, height,called_from_parent); - // *NOTE: we must check if child items exist because reshape is called from the - // LLView::initFromParams BEFORE postBuild is called and child controls are not exist yet - LLPanel* caption = findChild<LLPanel>("msg_caption", false); - LLChatMsgBox* msg_text = findChild<LLChatMsgBox>("msg_text" ,false); - if(caption && msg_text) - { - LLRect caption_rect = caption->getRect(); - caption_rect.setLeftTopAndSize( 2, height, width - 4, caption_rect.getHeight()); - caption->reshape( width - 4, caption_rect.getHeight(), 1); - caption->setRect(caption_rect); - - LLRect msg_text_rect = msg_text->getRect(); - msg_text_rect.setLeftTopAndSize( msg_left_offset, height - caption_rect.getHeight() , width - msg_left_offset - msg_right_offset, height - caption_rect.getHeight()); - msg_text->reshape( width - msg_left_offset - msg_right_offset, height - caption_rect.getHeight(), 1); - msg_text->setRect(msg_text_rect); - } + LLUICtrl* msg_text = getChild<LLUICtrl>("msg_text", false); + LLUICtrl* icon = getChild<LLUICtrl>("avatar_icon", false); + + LLRect msg_text_rect = msg_text->getRect(); + LLRect avatar_rect = icon->getRect(); + + avatar_rect.setLeftTopAndSize(2,height-2,avatar_rect.getWidth(),avatar_rect.getHeight()); + icon->setRect(avatar_rect); + + + msg_text_rect.setLeftTopAndSize( avatar_rect.mRight + msg_left_offset, + height - msg_height_pad, + width - avatar_rect.mRight - msg_left_offset - msg_right_offset, + height - 2*msg_height_pad); + msg_text->reshape( msg_text_rect.getWidth(), msg_text_rect.getHeight(), 1); + msg_text->setRect(msg_text_rect); } BOOL LLNearbyChatToastPanel::postBuild() @@ -102,37 +87,63 @@ BOOL LLNearbyChatToastPanel::postBuild() return LLPanel::postBuild(); } - -std::string LLNearbyChatToastPanel::appendTime() +void LLNearbyChatToastPanel::addMessage(LLSD& notification) { - time_t utc_time; - utc_time = time_corrected(); - std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" - +LLTrans::getString("TimeMin")+"] "; + std::string messageText = notification["message"].asString(); // UTF-8 line of text - LLSD substitution; + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); - substitution["datetime"] = (S32) utc_time; - LLStringUtil::format (timeStr, substitution); + std::string color_name = notification["text_color"].asString(); + + LLColor4 textColor = LLUIColorTable::instance().getColor(color_name); + textColor.mV[VALPHA] =notification["color_alpha"].asReal(); + + S32 font_size = notification["font_size"].asInteger(); - return timeStr; -} + LLFontGL* messageFont; + switch(font_size) + { + case 0: messageFont = LLFontGL::getFontSansSerifSmall(); break; + default: + case 1: messageFont = LLFontGL::getFontSansSerif(); break; + case 2: messageFont = LLFontGL::getFontSansSerifBig(); break; + } + //append text + { + LLStyle::Params style_params; + style_params.color(textColor); + std::string font_name = LLFontGL::nameFromFont(messageFont); + std::string font_style_size = LLFontGL::sizeFromFont(messageFont); + style_params.font.name(font_name); + style_params.font.size(font_style_size); + int chat_type = notification["chat_type"].asInteger(); + + if(notification["chat_style"].asInteger()== CHAT_STYLE_IRC) + { + messageText = messageText.substr(3); + style_params.font.style = "ITALIC"; + } + else if( chat_type == CHAT_TYPE_SHOUT) + { + style_params.font.style = "BOLD"; + } + else if( chat_type == CHAT_TYPE_WHISPER) + { + style_params.font.style = "ITALIC"; + } + msg_text->appendText(messageText, TRUE, style_params); + } + + snapToMessageHeight(); -void LLNearbyChatToastPanel::addText (const std::string& message , const LLStyle::Params& input_params) -{ - LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); - msg_text->addText(message , input_params); - mMessages.push_back(message); } void LLNearbyChatToastPanel::init(LLSD& notification) { - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - - mText = notification["message"].asString(); // UTF-8 line of text - mFromName = notification["from"].asString(); // agent or object name + std::string messageText = notification["message"].asString(); // UTF-8 line of text + std::string fromName = notification["from"].asString(); // agent or object name mFromID = notification["from_id"].asUUID(); // agent id or object id int sType = notification["source"].asInteger(); @@ -140,192 +151,121 @@ void LLNearbyChatToastPanel::init(LLSD& notification) std::string color_name = notification["text_color"].asString(); - mTextColor = LLUIColorTable::instance().getColor(color_name); - mTextColor.mV[VALPHA] =notification["color_alpha"].asReal(); + LLColor4 textColor = LLUIColorTable::instance().getColor(color_name); + textColor.mV[VALPHA] =notification["color_alpha"].asReal(); S32 font_size = notification["font_size"].asInteger(); + + LLFontGL* messageFont; switch(font_size) { - case 0: - mFont = LLFontGL::getFontSansSerifSmall(); - break; + case 0: messageFont = LLFontGL::getFontSansSerifSmall(); break; default: - case 1: - mFont = LLFontGL::getFontSansSerif(); - break; - case 2: - mFont = LLFontGL::getFontSansSerifBig(); - break; + case 1: messageFont = LLFontGL::getFontSansSerif(); break; + case 2: messageFont = LLFontGL::getFontSansSerifBig(); break; } - LLStyle::Params style_params; - style_params.color(mTextColor); -// style_params.font(mFont); - std::string font_name = LLFontGL::nameFromFont(mFont); - std::string font_style_size = LLFontGL::sizeFromFont(mFont); - style_params.font.name(font_name); - style_params.font.size(font_style_size); + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); + + msg_text->setText(std::string("")); std::string str_sender; if(gAgentID != mFromID) - str_sender = mFromName; + str_sender = fromName; else - str_sender = LLTrans::getString("You");; + str_sender = LLTrans::getString("You"); - caption->getChild<LLTextBox>("sender_name", false)->setText(str_sender , style_params); - - LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); + str_sender+=" "; + //append user name + { + LLStyle::Params style_params_name; + + LLColor4 userNameColor = LLUIColorTable::instance().getColor("ChatToastAgentNameColor"); + + style_params_name.color(userNameColor); + + std::string font_name = LLFontGL::nameFromFont(messageFont); + std::string font_style_size = LLFontGL::sizeFromFont(messageFont); + style_params_name.font.name(font_name); + style_params_name.font.size(font_style_size); + + msg_text->appendText(str_sender, FALSE, style_params_name); + + } - if(notification["chat_style"].asInteger()== CHAT_STYLE_IRC) + //append text { - if (mFromName.size() > 0) + LLStyle::Params style_params; + style_params.color(textColor); + std::string font_name = LLFontGL::nameFromFont(messageFont); + std::string font_style_size = LLFontGL::sizeFromFont(messageFont); + style_params.font.name(font_name); + style_params.font.size(font_style_size); + + int chat_type = notification["chat_type"].asInteger(); + + if(notification["chat_style"].asInteger()== CHAT_STYLE_IRC) { + messageText = messageText.substr(3); style_params.font.style = "ITALIC"; - - msg_text->setText(mFromName, style_params); } - mText = mText.substr(3); - style_params.font.style = "ITALIC"; -#define INFINITE_REFLOW_BUG 0 -#if INFINITE_REFLOW_BUG - // This causes LLTextBase::reflow() to infinite loop until the viewer - // runs out of memory, throws a bad_alloc exception from std::vector - // in mLineInfoList, and the main loop catches it and continues. - // It appears to be caused by addText() adding a line separator in the - // middle of a line. See EXT-2579, EXT-1949 - msg_text->addText(mText,style_params); -#else - msg_text->appendText(mText, FALSE, style_params); -#endif - } - else - { - msg_text->setText(mText, style_params); + else if( chat_type == CHAT_TYPE_SHOUT) + { + style_params.font.style = "BOLD"; + } + else if( chat_type == CHAT_TYPE_WHISPER) + { + style_params.font.style = "ITALIC"; + } + msg_text->appendText(messageText, FALSE, style_params); } - - LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); - if(mSourceType != CHAT_SOURCE_AGENT) - msg_inspector->setVisible(false); - - mMessages.clear(); - - snapToMessageHeight (); + snapToMessageHeight(); mIsDirty = true;//will set Avatar Icon in draw } -void LLNearbyChatToastPanel::setMessage (const LLChat& chat_msg) -{ - LLSD notification; - notification["message"] = chat_msg.mText; - notification["from"] = chat_msg.mFromName; - notification["from_id"] = chat_msg.mFromID; - notification["time"] = chat_msg.mTime; - notification["source"] = (S32)chat_msg.mSourceType; - notification["chat_type"] = (S32)chat_msg.mChatType; - notification["chat_style"] = (S32)chat_msg.mChatStyle; - - std::string r_color_name="White"; - F32 r_color_alpha = 1.0f; - LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha); - - notification["text_color"] = r_color_name; - notification["color_alpha"] = r_color_alpha; - - notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ; - init(notification); - -} - void LLNearbyChatToastPanel::snapToMessageHeight () { LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); - S32 new_height = text_box->getTextPixelHeight() + msg_height_pad; + S32 new_height = llmax (text_box->getTextPixelHeight() + 2*text_box->getVPad() + 2*msg_height_pad, 25); + LLRect panel_rect = getRect(); - S32 caption_height = 0; - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - caption_height = caption->getRect().getHeight(); - - panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), caption_height + new_height); + panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), new_height); - reshape( getRect().getWidth(), caption_height + new_height, 1); + reshape( getRect().getWidth(), getRect().getHeight(), 1); setRect(panel_rect); } - -void LLNearbyChatToastPanel::setWidth(S32 width) -{ - LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); - text_box->reshape(width - msg_left_offset - msg_right_offset,100/*its not magic number, we just need any number*/); - - LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); - - LLStyle::Params style_params; - style_params.color(mTextColor); - style_params.font(mFont); - - - if(mText.length()) - msg_text->setText(mText, style_params); - - for(size_t i=0;i<mMessages.size();++i) - msg_text->addText(mMessages[i] , style_params); - - setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width , getRect().mBottom)); - snapToMessageHeight (); -} - void LLNearbyChatToastPanel::onMouseLeave (S32 x, S32 y, MASK mask) { - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); - msg_inspector->setVisible(false); } void LLNearbyChatToastPanel::onMouseEnter (S32 x, S32 y, MASK mask) { if(mSourceType != CHAT_SOURCE_AGENT) return; - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); - msg_inspector->setVisible(true); } BOOL LLNearbyChatToastPanel::handleMouseDown (S32 x, S32 y, MASK mask) { if(mSourceType != CHAT_SOURCE_AGENT) return LLPanel::handleMouseDown(x,y,mask); - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); - S32 local_x = x - msg_inspector->getRect().mLeft - caption->getRect().mLeft; - S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom; - if(msg_inspector->pointInView(local_x, local_y)) - { - LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mFromID)); - } - else - { - LLFloaterReg::showInstance("nearby_chat",LLSD()); - } + LLFloaterReg::showInstance("nearby_chat",LLSD()); return LLPanel::handleMouseDown(x,y,mask); } void LLNearbyChatToastPanel::setHeaderVisibility(EShowItemHeader e) { - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - - LLUICtrl* icon = caption->getChild<LLUICtrl>("avatar_icon", false); - LLUICtrl* name = caption->getChild<LLUICtrl>("sender_name", false); - - icon->setVisible(e == CHATITEMHEADER_SHOW_ONLY_ICON || e==CHATITEMHEADER_SHOW_BOTH); - name->setVisible(e == CHATITEMHEADER_SHOW_ONLY_NAME || e==CHATITEMHEADER_SHOW_BOTH); + LLUICtrl* icon = getChild<LLUICtrl>("avatar_icon", false); + if(icon) + icon->setVisible(e == CHATITEMHEADER_SHOW_ONLY_ICON || e==CHATITEMHEADER_SHOW_BOTH); } @@ -339,11 +279,10 @@ bool LLNearbyChatToastPanel::canAddText () BOOL LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLPanel* caption = getChild<LLPanel>("msg_caption", false); - LLUICtrl* avatar_icon = caption->getChild<LLUICtrl>("avatar_icon", false); + LLUICtrl* avatar_icon = getChild<LLUICtrl>("avatar_icon", false); - S32 local_x = x - avatar_icon->getRect().mLeft - caption->getRect().mLeft; - S32 local_y = y - avatar_icon->getRect().mBottom - caption->getRect().mBottom; + S32 local_x = x - avatar_icon->getRect().mLeft; + S32 local_y = y - avatar_icon->getRect().mBottom; //eat message for avatar icon if msg was from object if(avatar_icon->pointInView(local_x, local_y) && mSourceType != CHAT_SOURCE_AGENT) @@ -354,9 +293,12 @@ void LLNearbyChatToastPanel::draw() { if(mIsDirty) { - LLPanel* caption = findChild<LLPanel>("msg_caption", false); - if(caption) - caption->getChild<LLAvatarIconCtrl>("avatar_icon", false)->setValue(mFromID); + LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false); + if(icon) + { + icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); + icon->setValue(mFromID); + } mIsDirty = false; } LLToastPanelBase::draw(); diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index a65bfedd09..0a85c52401 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -59,9 +59,8 @@ public: const LLUUID& getFromID() const { return mFromID;} - void addText (const std::string& message , const LLStyle::Params& input_params = LLStyle::Params()); - void setMessage (const LLChat& msg); - void setWidth (S32 width); + //void addText (const std::string& message , const LLStyle::Params& input_params = LLStyle::Params()); + //void setMessage (const LLChat& msg); void snapToMessageHeight (); bool canAddText (); @@ -78,22 +77,16 @@ public: BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual void init(LLSD& data); + virtual void addMessage(LLSD& data); virtual void draw(); -private: - - std::string appendTime (); + const LLUUID& messageID() const { return mFromID;} private: - std::string mText; // UTF-8 line of text - std::string mFromName; // agent or object name LLUUID mFromID; // agent id or object id EChatSourceType mSourceType; - LLColor4 mTextColor; - LLFontGL* mFont; - + - std::vector<std::string> mMessages; bool mIsDirty; }; diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 92e958b32d..764aff68c9 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -215,17 +215,38 @@ void LLFloaterCamera::onOpen(const LLSD& key) getDockTongue(), LLDockControl::TOP)); mZoom->onOpen(key); + + // Returns to previous mode, see EXT-2727(View tool should remember state). + // In case floater was just hidden and it isn't reset the mode + // just update state to current one. Else go to previous. + if ( !mClosed ) + updateState(); + else + toPrevMode(); + mClosed = FALSE; } void LLFloaterCamera::onClose(bool app_quitting) { //We don't care of camera mode if app is quitting - if(!app_quitting) - switchMode(CAMERA_CTRL_MODE_ORBIT); + if(app_quitting) + return; + // When mCurrMode is in CAMERA_CTRL_MODE_ORBIT + // switchMode won't modify mPrevMode, so force it here. + // It is needed to correctly return to previous mode on open, see EXT-2727. + if (mCurrMode == CAMERA_CTRL_MODE_ORBIT) + mPrevMode = CAMERA_CTRL_MODE_ORBIT; + + // HACK: Should always close as docked to prevent toggleInstance without calling onOpen. + if ( !isDocked() ) + setDocked(true); + switchMode(CAMERA_CTRL_MODE_ORBIT); + mClosed = TRUE; } LLFloaterCamera::LLFloaterCamera(const LLSD& val) : LLTransientDockableFloater(NULL, true, val), + mClosed(FALSE), mCurrMode(CAMERA_CTRL_MODE_ORBIT), mPrevMode(CAMERA_CTRL_MODE_ORBIT) { diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h index 4873a34e00..5d44b4944d 100644 --- a/indra/newview/llfloatercamera.h +++ b/indra/newview/llfloatercamera.h @@ -109,6 +109,7 @@ private: void assignButton2Mode(ECameraControlMode mode, const std::string& button_name); + BOOL mClosed; ECameraControlMode mPrevMode; ECameraControlMode mCurrMode; std::map<ECameraControlMode, LLButton*> mMode2Button; diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 0f8e4c10d7..9d05d9de34 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -304,7 +304,7 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur { font_style = "BOLD"; } - + item_name = gesture->mName; element["columns"][0]["column"] = "trigger"; element["columns"][0]["value"] = gesture->mTrigger; element["columns"][0]["font"]["name"] = "SANSSERIF"; diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 77a2cbcfca..18ff53c127 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -73,6 +73,7 @@ LLGestureManager::LLGestureManager() mActive(), mLoadingCount(0) { + mRetryIfMissing = true; gInventory.addObserver(this); } @@ -984,7 +985,9 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, else { // Watch this item and set gesture name when item exists in inventory - self.watchItem(item_id); + item_ref_t ids; + ids.push_back(item_id); + self.fetchItems(ids); } self.mActive[item_id] = gesture; @@ -1177,6 +1180,7 @@ void LLGestureManager::getItemIDs(std::vector<LLUUID>* ids) void LLGestureManager::done() { + bool notify = false; for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) { if(it->second && it->second->mName.empty()) @@ -1185,10 +1189,14 @@ void LLGestureManager::done() if(item) { it->second->mName = item->getName(); + notify = true; } } } - notifyObservers(); + if(notify) + { + notifyObservers(); + } } // static diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 094ca13798..e80eea9ae9 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -54,7 +54,7 @@ public: virtual void changed() = 0; }; -class LLGestureManager : public LLSingleton<LLGestureManager>, public LLInventoryCompletionObserver +class LLGestureManager : public LLSingleton<LLGestureManager>, public LLInventoryFetchObserver { public: diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index ee93a9349a..310eaaec27 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -529,7 +529,6 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void* //in disconnected state IM input editor should be disabled self->mInputEditor->setEnabled(!gDisconnected); } - self->mChatHistory->setCursorAndScrollToEnd(); } // static diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index c096b5220a..2f88578739 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -165,6 +165,11 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& { mVoiceChannel = new LLVoiceChannelGroup(session_id, name); } + + if(mVoiceChannel) + { + mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2)); + } mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); // All participants will be added to the list of people we've recently interacted with. @@ -191,6 +196,50 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this); } +void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) +{ + bool is_p2p_session = dynamic_cast<LLVoiceChannelP2P*>(mVoiceChannel); + bool is_incoming_call = false; + std::string other_avatar_name; + + if(is_p2p_session) + { + is_incoming_call = static_cast<LLVoiceChannelP2P*>(mVoiceChannel)->isIncomingCall(); + gCacheName->getFullName(mOtherParticipantID, other_avatar_name); + + if(is_incoming_call) + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, other_avatar_name, mOtherParticipantID, "Started a voice call"); + break; + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, "You", gAgent.getID(), "Joined the voice call"); + default: + break; + } + } + else // outgoing call + { + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + LLIMModel::getInstance()->addMessage(mSessionID, "You", gAgent.getID(), "Started a voice call"); + break; + case LLVoiceChannel::STATE_CONNECTED : + LLIMModel::getInstance()->addMessage(mSessionID, other_avatar_name, mOtherParticipantID, "Joined the voice call"); + default: + break; + } + } + } + else // group || ad-hoc calls + { + + } +} + LLIMModel::LLIMSession::~LLIMSession() { delete mSpeakers; @@ -427,19 +476,17 @@ bool LLIMModel::proccessOnlineOfflineNotification( } bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */) { + const std::string& utf8_text, bool log2file /* = true */) +{ LLIMSession* session = findIMSession(session_id); - if (!session) + if (!session) { llwarns << "session " << session_id << "does not exist " << llendl; return false; } - addToHistory(session_id, from, from_id, utf8_text); - if (log2file) logToFile(session_id, from, from_id, utf8_text); - - session->mNumUnread++; + addMessageSilently(*session, from, from_id, utf8_text, log2file); // notify listeners LLSD arg; @@ -454,6 +501,15 @@ bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, co return true; } +void LLIMModel::addMessageSilently(LLIMSession& session, const std::string& from, const LLUUID& from_id, + const std::string& utf8_text, bool log2file /* = true */) +{ + addToHistory(session.mSessionID, from, from_id, utf8_text); + if (log2file) logToFile(session.mSessionID, from, from_id, utf8_text); + + session.mNumUnread++; +} + const std::string& LLIMModel::getName(const LLUUID& session_id) const { @@ -1150,7 +1206,7 @@ BOOL LLOutgoingCallDialog::postBuild() childSetAction("Cancel", onCancel, this); // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), this, getDockTongue(), LLDockControl::TOP, boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); @@ -1227,7 +1283,7 @@ void LLIncomingCallDialog::onOpen(const LLSD& key) } // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), this, getDockTongue(), LLDockControl::TOP, boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); } diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 62a54bc081..72fd006222 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -61,6 +61,7 @@ public: void sessionInitReplyReceived(const LLUUID& new_session_id); void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time); + void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state); static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); LLUUID mSessionID; @@ -145,6 +146,11 @@ public: bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true); /** + * Adds message without new message notification. + */ + void addMessageSilently(LLIMSession& session, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true); + + /** * Add a system message to an IM Model */ bool proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 941ccc227c..9caa863bd8 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -77,12 +77,12 @@ std::string LLLogChat::timestamp(bool withdate) +LLTrans::getString ("TimeMonth")+"]/[" +LLTrans::getString ("TimeDay")+"] [" +LLTrans::getString ("TimeHour")+"]:[" - +LLTrans::getString ("TimeMin")+"] "; + +LLTrans::getString ("TimeMin")+"]"; } else { timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" - + LLTrans::getString ("TimeMin")+"] "; + + LLTrans::getString ("TimeMin")+"]"; } LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 80a6cc343f..8f1dec1431 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -130,6 +130,21 @@ void LLNearbyChat::applySavedVariables() } } +std::string appendTime() +{ + time_t utc_time; + utc_time = time_corrected(); + std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" + +LLTrans::getString("TimeMin")+"] "; + + LLSD substitution; + + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + + return timeStr; +} + void LLNearbyChat::addMessage(const LLChat& chat) { if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) @@ -150,11 +165,18 @@ void LLNearbyChat::addMessage(const LLChat& chat) return; } } + + bool use_plain_text_chat_history = gSavedSettings.getBOOL("PlainTextChatHistory"); if (!chat.mMuted) { std::string message = chat.mText; - std::string prefix = message.substr(0, 4); + + + LLChat& tmp_chat = const_cast<LLChat&>(chat); + + if(tmp_chat.mTimeStr.empty()) + tmp_chat.mTimeStr = appendTime(); if (chat.mChatStyle == CHAT_STYLE_IRC) { @@ -173,7 +195,7 @@ void LLNearbyChat::addMessage(const LLChat& chat) append_style_params.font.style = "ITALIC"; LLChat add_chat=chat; add_chat.mText = chat.mFromName + " "; - mChatHistory->appendMessage(add_chat, false, append_style_params); + mChatHistory->appendMessage(add_chat, use_plain_text_chat_history, append_style_params); } message = message.substr(3); @@ -182,7 +204,7 @@ void LLNearbyChat::addMessage(const LLChat& chat) } else { - mChatHistory->appendMessage(chat); + mChatHistory->appendMessage(chat,use_plain_text_chat_history); } } } @@ -206,13 +228,23 @@ bool LLNearbyChat::onNearbyChatCheckContextMenuItem(const LLSD& userdata) return false; } -void LLNearbyChat::onOpen(const LLSD& key ) +void LLNearbyChat::setVisible(BOOL visible) { - LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); - if(chat_channel) + if(visible) { - chat_channel->removeToastsFromChannel(); + LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + if(chat_channel) + { + chat_channel->removeToastsFromChannel(); + } } + + LLDockableFloater::setVisible(visible); +} + +void LLNearbyChat::onOpen(const LLSD& key ) +{ + LLDockableFloater::onOpen(key); } void LLNearbyChat::setRect (const LLRect &rect) diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index 561c2d3677..efcaf4263b 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -53,6 +53,8 @@ public: /*virtual*/ void onOpen (const LLSD& key); + /*virtual*/ void setVisible(BOOL visible); + virtual void setRect (const LLRect &rect); private: diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 74a75d0369..b0b6db682c 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -52,8 +52,6 @@ using namespace LLNotificationsUI; LLToastPanelBase* createToastPanel() { LLNearbyChatToastPanel* item = LLNearbyChatToastPanel::createInstance(); - static S32 chat_item_width = 304; - item->setWidth(chat_item_width); return item; } @@ -169,6 +167,29 @@ void LLNearbyChatScreenChannel::addNotification(LLSD& notification) //look in pool. if there is any message if(mStopProcessing) return; + + /* + find last toast and check ID + */ + + if(m_active_toasts.size()) + { + LLUUID fromID = notification["from_id"].asUUID(); // agent id or object id + LLToast* toast = m_active_toasts[0]; + LLNearbyChatToastPanel* panel = dynamic_cast<LLNearbyChatToastPanel*>(toast->getPanel()); + + if(panel && panel->messageID() == fromID && panel->canAddText()) + { + panel->addMessage(notification); + toast->reshapeToPanel(); + toast->resetTimer(); + + arrangeToasts(); + return; + } + } + + if(m_toast_pool.empty()) { diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 29664e1919..d42b0148d6 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -39,6 +39,7 @@ //#include "llnotificationsutil.h" #include "llchannelmanager.h" #include "llchat.h" +#include "llnotificationptr.h" namespace LLNotificationsUI { @@ -256,6 +257,20 @@ protected: void onRejectToast(LLUUID& id); }; +class LLHandlerUtil +{ +public: + /** + * Checks sufficient conditions to log notification message to IM session. + */ + static bool canLogToIM(const LLNotificationPtr& notification); + + /** + * Writes notification message to IM session. + */ + static void logToIM(const LLNotificationPtr& notification); +}; + } #endif diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp new file mode 100644 index 0000000000..e1236b935e --- /dev/null +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -0,0 +1,88 @@ +/** + * @file llnotificationofferhandler.cpp + * @brief Provides set of utility methods for notifications processing. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-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" // must be first include + +#include "llnotificationhandler.h" +#include "llnotifications.h" +#include "llimview.h" + +using namespace LLNotificationsUI; + +const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), + REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM( + "ObjectGiveItem"), OBJECT_GIVE_ITEM_UNKNOWN_USER( + "ObjectGiveItemUnknownUser"); + +// static +bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) +{ + return GRANTED_MODIFY_RIGHTS == notification->getName() + || REVOKED_MODIFY_RIGHTS == notification->getName(); +} + +// static +void LLHandlerUtil::logToIM(const LLNotificationPtr& notification) +{ + // add message to IM + const std::string + name = + notification->getSubstitutions().has("NAME") ? notification->getSubstitutions()["NAME"] + : notification->getSubstitutions()["[NAME]"]; + + // don't create IM session with objects, it's necessary condition to log + if (notification->getName() != OBJECT_GIVE_ITEM && notification->getName() + != OBJECT_GIVE_ITEM_UNKNOWN_USER) + { + 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) + { + session_id = LLIMMgr::instance().addSession(name, + IM_NOTHING_SPECIAL, from_id); + session = LLIMModel::instance().findIMSession(session_id); + } + + if (session == NULL) + { + llerrs << "session " << session_id << "does not exist " << llendl; + return; + } + + LLIMModel::instance().addMessageSilently(*session, name, from_id, + notification->getMessage()); + } +} diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 45b5e88472..cfe7fd09ac 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -37,8 +37,6 @@ #include "lltoastnotifypanel.h" #include "llviewercontrol.h" #include "llviewerwindow.h" -#include "llimview.h" -#include "llimfloater.h" #include "llnotificationmanager.h" #include "llnotifications.h" @@ -92,27 +90,7 @@ bool LLOfferHandler::processNotification(const LLSD& notify) if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") { - // add message to IM - const std::string - name = - notification->getSubstitutions().has("NAME") ? notification->getSubstitutions()["NAME"] - : notification->getSubstitutions()["[NAME]"]; - - // don't create IM session with objects - if (notification->getName() != "ObjectGiveItem" - && notification->getName() != "ObjectGiveItemUnknownUser") - { - LLUUID from_id = notification->getPayload()["from_id"]; - LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, - from_id); - if (!LLIMMgr::instance().hasSession(session_id)) - { - session_id = LLIMMgr::instance().addSession(name, - IM_NOTHING_SPECIAL, from_id); - } - LLIMMgr::instance().addMessage(session_id, LLUUID(), name, - notification->getMessage()); - } + LLHandlerUtil::logToIM(notification); LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification); diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 471c254bbc..6f91b6e58b 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -45,6 +45,7 @@ using namespace LLNotificationsUI; static const std::string SCRIPT_DIALOG ("ScriptDialog"); static const std::string SCRIPT_DIALOG_GROUP ("ScriptDialogGroup"); +static const std::string SCRIPT_LOAD_URL ("LoadWebPage"); //-------------------------------------------------------------------------- LLScriptHandler::LLScriptHandler(e_notification_type type, const LLSD& id) @@ -95,7 +96,12 @@ bool LLScriptHandler::processNotification(const LLSD& notify) if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") { - if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) + if (LLHandlerUtil::canLogToIM(notification)) + { + LLHandlerUtil::logToIM(notification); + } + + if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName() || SCRIPT_LOAD_URL == notification->getName()) { LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID()); } @@ -121,7 +127,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify) } else if (notify["sigtype"].asString() == "delete") { - if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) + if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName() || SCRIPT_LOAD_URL == notification->getName()) { LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID()); } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 6f753b6176..97c1e96175 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -48,6 +48,9 @@ #include "llscrollcontainer.h" #include "llavatariconctrl.h" #include "llweb.h" +#include "llfloaterworldmap.h" +#include "llfloaterreg.h" +#include "llnotificationsutil.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLDropTarget @@ -150,6 +153,8 @@ BOOL LLPanelAvatarNotes::postBuild() childSetCommitCallback("call", boost::bind(&LLPanelAvatarNotes::onCallButtonClick, this), NULL); childSetCommitCallback("teleport", boost::bind(&LLPanelAvatarNotes::onTeleportButtonClick, this), NULL); childSetCommitCallback("share", boost::bind(&LLPanelAvatarNotes::onShareButtonClick, this), NULL); + childSetCommitCallback("show_on_map_btn", (boost::bind( + &LLPanelAvatarNotes::onMapButtonClick, this)), NULL); LLTextEditor* te = getChild<LLTextEditor>("notes_edit"); te->setCommitCallback(boost::bind(&LLPanelAvatarNotes::onCommitNotes,this)); @@ -195,6 +200,46 @@ void LLPanelAvatarNotes::onCommitNotes() LLAvatarPropertiesProcessor::getInstance()-> sendNotes(getAvatarId(),notes); } +void LLPanelAvatarNotes::rightsConfirmationCallback(const LLSD& notification, + const LLSD& response, S32 rights) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights( + getAvatarId(), rights); + } + else + { + childSetValue("objects_check", + childGetValue("objects_check").asBoolean() ? FALSE : TRUE); + } +} + +void LLPanelAvatarNotes::confirmModifyRights(bool grant, S32 rights) +{ + std::string first, last; + LLSD args; + if (gCacheName->getName(getAvatarId(), first, last)) + { + args["FIRST_NAME"] = first; + args["LAST_NAME"] = last; + } + + if (grant) + { + LLNotificationsUtil::add("GrantModifyRights", args, LLSD(), + boost::bind(&LLPanelAvatarNotes::rightsConfirmationCallback, this, + _1, _2, rights)); + } + else + { + LLNotificationsUtil::add("RevokeModifyRights", args, LLSD(), + boost::bind(&LLPanelAvatarNotes::rightsConfirmationCallback, this, + _1, _2, rights)); + } +} + void LLPanelAvatarNotes::onCommitRights() { S32 rights = 0; @@ -206,7 +251,14 @@ void LLPanelAvatarNotes::onCommitRights() if(childGetValue("objects_check").asBoolean()) rights |= LLRelationship::GRANT_MODIFY_OBJECTS; - LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(),rights); + const LLRelationship* buddy_relationship = + LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + bool allow_modify_objects = childGetValue("objects_check").asBoolean(); + if (buddy_relationship->isRightGrantedTo( + LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) + { + confirmModifyRights(allow_modify_objects, rights); + } } void LLPanelAvatarNotes::processProperties(void* data, EAvatarProcessorType type) @@ -311,6 +363,7 @@ void LLPanelProfileTab::onOpen(const LLSD& key) // Update data even if we are viewing same avatar profile as some data might been changed. setAvatarId(key.asUUID()); updateData(); + updateButtons(); } void LLPanelProfileTab::scrollToTop() @@ -320,6 +373,22 @@ void LLPanelProfileTab::scrollToTop() scrollContainer->goToTop(); } +void LLPanelProfileTab::onMapButtonClick() +{ + std::string name; + gCacheName->getFullName(getAvatarId(), name); + gFloaterWorldMap->trackAvatar(getAvatarId(), name); + LLFloaterReg::showInstance("world_map"); +} + +void LLPanelProfileTab::updateButtons() +{ + bool enable_map_btn = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) + && gAgent.isGodlike() || is_agent_mappable(getAvatarId()); + + childSetEnabled("show_on_map_btn", enable_map_btn); +} + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -338,6 +407,8 @@ BOOL LLPanelAvatarProfile::postBuild() childSetCommitCallback("teleport",(boost::bind(&LLPanelAvatarProfile::onTeleportButtonClick,this)),NULL); childSetCommitCallback("overflow_btn", boost::bind(&LLPanelAvatarProfile::onOverflowButtonClicked, this), NULL); childSetCommitCallback("share",(boost::bind(&LLPanelAvatarProfile::onShareButtonClick,this)),NULL); + childSetCommitCallback("show_on_map_btn", (boost::bind( + &LLPanelAvatarProfile::onMapButtonClick, this)), NULL); LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; registrar.add("Profile.Pay", boost::bind(&LLPanelAvatarProfile::pay, this)); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 527e1c0d34..f54aeee4eb 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -106,6 +106,10 @@ protected: */ void scrollToTop(); + virtual void onMapButtonClick(); + + virtual void updateButtons(); + private: LLUUID mAvatarId; @@ -256,6 +260,9 @@ protected: */ void fillRightsData(); + void rightsConfirmationCallback(const LLSD& notification, + const LLSD& response, S32 rights); + void confirmModifyRights(bool grant, S32 rights); void onCommitRights(); void onCommitNotes(); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index da7922d657..b6c58808ae 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -42,6 +42,7 @@ #include "lliconctrl.h" #include "lllineeditor.h" #include "llnamelistctrl.h" +#include "llnotifications.h" #include "llnotificationsutil.h" #include "llnotify.h" #include "llpanelgrouproles.h" @@ -1101,10 +1102,33 @@ void LLPanelGroupMembersSubTab::handleEjectMembers() mMembersList->deleteSelectedItems(); + sendEjectNotifications(mGroupID, selected_members); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); } +void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const std::vector<LLUUID>& selected_members) +{ + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); + + if (group_data) + { + for (std::vector<LLUUID>::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i) + { + LLSD args; + std::string name; + + gCacheName->getFullName(*i, name); + + args["AVATAR_NAME"] = name; + args["GROUP_NAME"] = group_data->mName; + + LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); + } + } +} + void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, LLRoleMemberChangeType type) { @@ -1544,9 +1568,6 @@ void LLPanelGroupMembersSubTab::updateMembers() mPendingMemberUpdate = FALSE; // Rebuild the members list. - mMembersList->deleteAllItems(); - - lldebugs << "LLPanelGroupMembersSubTab::updateMembers()" << llendl; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) @@ -1563,7 +1584,12 @@ void LLPanelGroupMembersSubTab::updateMembers() { return; } - + + //cleanup list only for first iretation + if(mMemberProgress == gdatap->mMembers.begin()) + mMembersList->deleteAllItems(); + + LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); S32 i = 0; diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index b6e2245e70..bb3c9096cf 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -170,6 +170,7 @@ public: static void onEjectMembers(void*); void handleEjectMembers(); + void sendEjectNotifications(const LLUUID& group_id, const std::vector<LLUUID>& selected_members); static void onRoleCheck(LLUICtrl* check, void* user_data); void handleRoleCheck(const LLUUID& role_id, diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index fa6d16cfb1..405c95fc22 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -32,6 +32,8 @@ #include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" + #include "llpanelimcontrolpanel.h" #include "llagent.h" @@ -58,7 +60,7 @@ void LLPanelChatControlPanel::onEndCallButtonClicked() void LLPanelChatControlPanel::onOpenVoiceControlsClicked() { - // TODO: implement Voice Control Panel opening + LLFloaterReg::showInstance("voice_controls"); } void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) @@ -120,6 +122,7 @@ LLPanelIMControlPanel::LLPanelIMControlPanel() LLPanelIMControlPanel::~LLPanelIMControlPanel() { + LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarID, this); } BOOL LLPanelIMControlPanel::postBuild() @@ -169,7 +172,9 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) LLIMModel& im_model = LLIMModel::instance(); + LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarID, this); mAvatarID = im_model.getOtherParticipantID(session_id); + LLAvatarTracker::instance().addParticularFriendObserver(mAvatarID, this); // Disable "Add friend" button for friends. childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(mAvatarID)); @@ -198,6 +203,12 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) } } +//virtual +void LLPanelIMControlPanel::changed(U32 mask) +{ + childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(mAvatarID)); +} + void LLPanelIMControlPanel::nameUpdatedCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) { if ( id == mAvatarID ) diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index 7bfc432ef2..a590232a0b 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -35,6 +35,7 @@ #include "llpanel.h" #include "llvoicechannel.h" +#include "llcallingcard.h" class LLSpeakerMgr; class LLAvatarList; @@ -66,7 +67,7 @@ private: }; -class LLPanelIMControlPanel : public LLPanelChatControlPanel +class LLPanelIMControlPanel : public LLPanelChatControlPanel, LLFriendObserver { public: LLPanelIMControlPanel(); @@ -76,6 +77,9 @@ public: void setSessionId(const LLUUID& session_id); + // LLFriendObserver trigger + virtual void changed(U32 mask); + protected: void nameUpdatedCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index e24fa14e1e..dafb970b30 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -730,13 +730,14 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const { return canSelectedBeModified(command_name); } - else if ( "sort_by_date" == command_name) - { - return mSortByDate; - } else if("create_pick" == command_name) { - return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); + std::set<LLUUID> selection; + if ( mCurrentSelectedList && mCurrentSelectedList->getRootFolder()->getSelectionList(selection) ) + { + return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() ); + } + return false; } else { diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index e6b6ec64bd..6771bb4170 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -73,6 +73,8 @@ static const std::string FRIENDS_TAB_NAME = "friends_panel"; static const std::string GROUP_TAB_NAME = "groups_panel"; static const std::string RECENT_TAB_NAME = "recent_panel"; +static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; + /** Comparator for comparing avatar items by last interaction date */ class LLAvatarItemRecentComparator : public LLAvatarItemComparator { @@ -467,7 +469,7 @@ LLPanelPeople::~LLPanelPeople() } -void LLPanelPeople::onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAvatarList* avatar_list) +void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list) { if(!avatar_list) { @@ -477,6 +479,7 @@ void LLPanelPeople::onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAva bool expanded = param.asBoolean(); + setAccordionCollapsedByUser(ctrl, !expanded); if(!expanded) { avatar_list->resetSelection(); @@ -550,11 +553,11 @@ BOOL LLPanelPeople::postBuild() LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all"); accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _2, mAllFriendList)); + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList)); accordion_tab = getChild<LLAccordionCtrlTab>("tab_online"); accordion_tab->setDropDownStateChangedCallback( - boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _2, mOnlineFriendList)); + boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList)); buttonSetAction("view_profile_btn", boost::bind(&LLPanelPeople::onViewProfileButtonClicked, this)); buttonSetAction("group_info_btn", boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this)); @@ -760,7 +763,13 @@ void LLPanelPeople::updateButtons() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); if (cur_panel) + { cur_panel->childSetEnabled("add_friend_btn", !is_friend); + if (friends_tab_active) + { + cur_panel->childSetEnabled("del_btn", multiple_selected); + } + } } buttonSetEnabled("teleport_btn", friends_tab_active && item_selected && isFriendOnline(selected_uuids.front())); @@ -931,6 +940,9 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) mRecentList->setNameFilter(mFilterSubString); mGroupList->setNameFilter(mFilterSubString); + setAccordionCollapsedByUser("tab_online", false); + setAccordionCollapsedByUser("tab_all", false); + showFriendsAccordionsIfNeeded(); } @@ -1309,8 +1321,12 @@ void LLPanelPeople::showAccordion(const std::string name, bool show) tab->setVisible(show); if(show) { - // expand accordion - tab->changeOpenClose(false); + // don't expand accordion if it was collapsed by user + if(!isAccordionCollapsedByUser(tab)) + { + // expand accordion + tab->changeOpenClose(false); + } } } @@ -1342,3 +1358,44 @@ void LLPanelPeople::onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion"); accordion->arrange(); } + +void LLPanelPeople::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed) +{ + if(!acc_tab) + { + llwarns << "Invalid parameter" << llendl; + return; + } + + LLSD param = acc_tab->getValue(); + param[COLLAPSED_BY_USER] = collapsed; + acc_tab->setValue(param); +} + +void LLPanelPeople::setAccordionCollapsedByUser(const std::string& name, bool collapsed) +{ + setAccordionCollapsedByUser(getChild<LLUICtrl>(name), collapsed); +} + +bool LLPanelPeople::isAccordionCollapsedByUser(LLUICtrl* acc_tab) +{ + if(!acc_tab) + { + llwarns << "Invalid parameter" << llendl; + return false; + } + + LLSD param = acc_tab->getValue(); + if(!param.has(COLLAPSED_BY_USER)) + { + return false; + } + return param[COLLAPSED_BY_USER].asBoolean(); +} + +bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name) +{ + return isAccordionCollapsedByUser(getChild<LLUICtrl>(name)); +} + +// EOF diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index d9dd76f3ac..5ac5bcc1d7 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -127,7 +127,7 @@ private: const std::vector<LLUUID>& ids, void*); - void onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAvatarList* avatar_list); + void onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list); void showAccordion(const std::string name, bool show); @@ -135,6 +135,11 @@ private: void onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param); + void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed); + void setAccordionCollapsedByUser(const std::string& name, bool collapsed); + bool isAccordionCollapsedByUser(LLUICtrl* acc_tab); + bool isAccordionCollapsedByUser(const std::string& name); + LLFilterEditor* mFilterEditor; LLTabContainer* mTabContainer; LLAvatarList* mOnlineFriendList; diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index b17b6d6fe9..b21b1c64b1 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -86,6 +86,9 @@ public: // parent panels failed to work (picks related code was in my profile panel) void setProfilePanel(LLPanelProfile* profile_panel); +protected: + /*virtual*/void updateButtons(); + private: void onClickDelete(); void onClickTeleport(); @@ -125,7 +128,6 @@ private: bool callbackDeleteClassified(const LLSD& notification, const LLSD& response); bool callbackTeleport(const LLSD& notification, const LLSD& response); - void updateButtons(); virtual void onDoubleClickPickItem(LLUICtrl* item); virtual void onDoubleClickClassifiedItem(LLUICtrl* item); diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index b82b994540..327048d4f3 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -52,6 +52,8 @@ // Used to limit time spent for items list update per frame. static const U32 ADD_LIMIT = 50; +static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; + class LLTeleportHistoryFlatItem : public LLPanel { public: @@ -254,6 +256,10 @@ BOOL LLTeleportHistoryPanel::postBuild() LLAccordionCtrlTab* tab = (LLAccordionCtrlTab*)*iter; tab->setRightMouseDownCallback(boost::bind(&LLTeleportHistoryPanel::onAccordionTabRightClick, this, _1, _2, _3, _4)); tab->setDisplayChildren(false); + tab->setDropDownStateChangedCallback(boost::bind(&LLTeleportHistoryPanel::onAccordionExpand, this, _1, _2)); + + // All accordion tabs are collapsed initially + setAccordionCollapsedByUser(tab, true); mItemContainers.put(tab); @@ -270,10 +276,18 @@ BOOL LLTeleportHistoryPanel::postBuild() // Open first 2 accordion tabs if (mItemContainers.size() > 1) - mItemContainers.get(mItemContainers.size() - 1)->setDisplayChildren(true); + { + LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 1); + tab->setDisplayChildren(true); + setAccordionCollapsedByUser(tab, false); + } if (mItemContainers.size() > 2) - mItemContainers.get(mItemContainers.size() - 2)->setDisplayChildren(true); + { + LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 2); + tab->setDisplayChildren(true); + setAccordionCollapsedByUser(tab, false); + } } getChild<LLPanel>("bottom_panel")->childSetAction("gear_btn",boost::bind(&LLTeleportHistoryPanel::onGearButtonClicked, this)); @@ -491,6 +505,18 @@ void LLTeleportHistoryPanel::refresh() LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 1 - tab_idx); tab->setVisible(true); + // Expand all accordion tabs when filtering + if(!mFilterSubString.empty()) + { + tab->setDisplayChildren(true); + } + // Restore each tab's expand state when not filtering + else + { + bool collapsed = isAccordionCollapsedByUser(tab); + tab->setDisplayChildren(!collapsed); + } + curr_flat_view = getFlatListViewFromTab(tab); } @@ -775,3 +801,26 @@ void LLTeleportHistoryPanel::onGearButtonClicked() LLMenuGL::showPopup(this, menu, menu_x, menu_y); } +void LLTeleportHistoryPanel::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed) +{ + LLSD param = acc_tab->getValue(); + param[COLLAPSED_BY_USER] = collapsed; + acc_tab->setValue(param); +} + +bool LLTeleportHistoryPanel::isAccordionCollapsedByUser(LLUICtrl* acc_tab) +{ + LLSD param = acc_tab->getValue(); + if(!param.has("acc_collapsed")) + { + return false; + } + return param[COLLAPSED_BY_USER].asBoolean(); +} + +void LLTeleportHistoryPanel::onAccordionExpand(LLUICtrl* ctrl, const LLSD& param) +{ + bool expanded = param.asBoolean(); + // Save accordion tab state to restore it in refresh() + setAccordionCollapsedByUser(ctrl, !expanded); +} diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h index a31ff34cb6..f646fea355 100644 --- a/indra/newview/llpanelteleporthistory.h +++ b/indra/newview/llpanelteleporthistory.h @@ -98,6 +98,10 @@ private: LLFlatListView* getFlatListViewFromTab(LLAccordionCtrlTab *); void onGearButtonClicked(); + void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed); + bool isAccordionCollapsedByUser(LLUICtrl* acc_tab); + void onAccordionExpand(LLUICtrl* ctrl, const LLSD& param); + LLTeleportHistoryStorage* mTeleportHistory; LLAccordionCtrl* mHistoryAccordion; diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 4ee9cba69c..68dc1b511f 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -47,10 +47,11 @@ #if LL_MSVC #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally #endif -LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list): +LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu/* = true*/): mSpeakerMgr(data_source), mAvatarList(avatar_list), mSortOrder(E_SORT_BY_NAME) +, mParticipantListMenu(NULL) { mSpeakerAddListener = new SpeakerAddListener(*this); mSpeakerRemoveListener = new SpeakerRemoveListener(*this); @@ -68,8 +69,15 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av // Set onAvatarListDoubleClicked as default on_return action. mAvatarList->setReturnCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList)); - mParticipantListMenu = new LLParticipantListMenu(*this); - mAvatarList->setContextMenu(mParticipantListMenu); + if (use_context_menu) + { + mParticipantListMenu = new LLParticipantListMenu(*this); + mAvatarList->setContextMenu(mParticipantListMenu); + } + else + { + mAvatarList->setContextMenu(NULL); + } //Lets fill avatarList with existing speakers LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); @@ -85,6 +93,7 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av mModeratorList.insert(speakerp->mID); } } + mAvatarList->setDirty(true); sort(); } diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h index 5e26c39fc8..ce61dd9b96 100644 --- a/indra/newview/llparticipantlist.h +++ b/indra/newview/llparticipantlist.h @@ -43,7 +43,7 @@ class LLParticipantList { LOG_CLASS(LLParticipantList); public: - LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list); + LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu = true); ~LLParticipantList(); void setSpeakingIndicatorsVisible(BOOL visible); diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index ee5fa46c9c..ee62d689b5 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -583,6 +583,17 @@ void LLSideTray::expandSideBar() mActiveTab->onOpen(key); reflectCollapseChange(); + + + std::string name = mActiveTab->getName(); + std::map<std::string,LLButton*>::const_iterator btn_it = + mTabButtons.find(name); + if (btn_it != mTabButtons.end()) + { + LLButton* btn = btn_it->second; + btn->setImageOverlay( mActiveTab->mImageSelected ); + } + } void LLSideTray::highlightFocused() diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp index 54f776ca6a..5edc4804ca 100644 --- a/indra/newview/llspeakbutton.cpp +++ b/indra/newview/llspeakbutton.cpp @@ -32,19 +32,14 @@ #include "llviewerprecompiledheaders.h" // must be first include -#include "llagent.h" -#include "llbottomtray.h" +#include "llbutton.h" #include "llfloaterreg.h" -#include "llvoiceclient.h" -#include "llvoicecontrolpanel.h" -#include "lltransientfloatermgr.h" -#include "llavatariconctrl.h" -#include "llbutton.h" -#include "llpanel.h" -#include "lltextbox.h" +#include "llagent.h" +#include "llbottomtray.h" +#include "llcallfloater.h" #include "lloutputmonitorctrl.h" -#include "llgroupmgr.h" +#include "lltransientfloatermgr.h" #include "llspeakbutton.h" @@ -72,7 +67,6 @@ void LLSpeakButton::draw() LLSpeakButton::LLSpeakButton(const Params& p) : LLUICtrl(p) -, mPrivateCallPanel(NULL) , mOutputMonitor(NULL) , mSpeakBtn(NULL) , mShowBtn(NULL) @@ -102,8 +96,8 @@ LLSpeakButton::LLSpeakButton(const Params& p) addChild(mShowBtn); LLTransientFloaterMgr::getInstance()->addControlView(mShowBtn); - mShowBtn->setClickedCallback(boost::bind(&LLSpeakButton::onClick_ShowBtn, this)); - mShowBtn->setToggleState(FALSE); +// mShowBtn->setClickedCallback(boost::bind(&LLSpeakButton::onClick_ShowBtn, this)); +// mShowBtn->setToggleState(FALSE); static const S32 MONITOR_RIGHT_PAD = 2; @@ -175,42 +169,3 @@ void LLSpeakButton::onMouseUp_SpeakBtn() gVoiceClient->inputUserControlState(down); } -void LLSpeakButton::onClick_ShowBtn() -{ - if(!mShowBtn->getToggleState()) - { - mPrivateCallPanel->onClickClose(mPrivateCallPanel); - delete mPrivateCallPanel; - mPrivateCallPanel = NULL; - mShowBtn->setToggleState(FALSE); - return; - } - - S32 x = mSpeakBtn->getRect().mLeft; - S32 y = 0; - - localPointToScreen(x, y, &x, &y); - - mPrivateCallPanel = new LLVoiceControlPanel; - getRootView()->addChild(mPrivateCallPanel); - - y = LLBottomTray::getInstance()->getRect().getHeight() + mPrivateCallPanel->getRect().getHeight(); - - LLRect rect; - rect.setLeftTopAndSize(x, y, mPrivateCallPanel->getRect().getWidth(), mPrivateCallPanel->getRect().getHeight()); - mPrivateCallPanel->setRect(rect); - - - LLAvatarListItem* item = new LLAvatarListItem(); - item->showLastInteractionTime(false); - item->showInfoBtn(true); - item->showSpeakingIndicator(true); - item->reshape(mPrivateCallPanel->getRect().getWidth(), item->getRect().getHeight(), FALSE); - - mPrivateCallPanel->addItem(item); - mPrivateCallPanel->setVisible(TRUE); - mPrivateCallPanel->setFrontmost(TRUE); - - mShowBtn->setToggleState(TRUE); -} - diff --git a/indra/newview/llspeakbutton.h b/indra/newview/llspeakbutton.h index 424ee5357a..6660b50240 100644 --- a/indra/newview/llspeakbutton.h +++ b/indra/newview/llspeakbutton.h @@ -36,7 +36,7 @@ #include "llinitparam.h" #include "lluictrl.h" -class LLVoiceControlPanel; +class LLCallFloater; class LLButton; class LLOutputMonitorCtrl; @@ -86,12 +86,10 @@ protected: void onMouseDown_SpeakBtn(); void onMouseUp_SpeakBtn(); - void onClick_ShowBtn(); - private: LLButton* mSpeakBtn; LLButton* mShowBtn; - LLVoiceControlPanel* mPrivateCallPanel; + LLHandle<LLFloater> mPrivateCallPanel; LLOutputMonitorCtrl* mOutputMonitor; }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e7fe85bdf0..db8bda008e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -101,7 +101,6 @@ #include "llfeaturemanager.h" #include "llfirstuse.h" #include "llfloaterchat.h" -#include "llfloatergesture.h" #include "llfloaterhud.h" #include "llfloaterland.h" #include "llfloaterpreference.h" @@ -299,23 +298,6 @@ namespace }; } -class LLGestureInventoryFetchObserver : public LLInventoryFetchObserver -{ -public: - LLGestureInventoryFetchObserver() {} - virtual void done() - { - // we've downloaded all the items, so repaint the dialog - LLFloaterGesture* floater = LLFloaterReg::findTypedInstance<LLFloaterGesture>("gestures"); - if (floater) - { - floater->refreshAll(); - } - gInventory.removeObserver(this); - delete this; - } -}; - void update_texture_fetch() { LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread @@ -1825,11 +1807,8 @@ bool idle_startup() item_ids.push_back(item_id); } } - - LLGestureInventoryFetchObserver* fetch = new LLGestureInventoryFetchObserver(); - fetch->fetchItems(item_ids); - // deletes itself when done - gInventory.addObserver(fetch); + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureManager::instance().fetchItems(item_ids); } } gDisplaySwapBuffers = TRUE; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index dc22a243eb..4915720036 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -42,6 +42,7 @@ #include "llfloaterbuycurrency.h" #include "llfloaterchat.h" #include "llfloaterlagmeter.h" +#include "llfloatervolumepulldown.h" #include "llfloaterregioninfo.h" #include "llfloaterscriptdebug.h" #include "llhudicon.h" @@ -159,6 +160,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect) mBtnVolume = getChild<LLButton>( "volume_btn" ); mBtnVolume->setClickedCallback( onClickVolume, this ); + mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this)); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2)); @@ -203,7 +205,6 @@ LLStatusBar::LLStatusBar(const LLRect& rect) addChild(mSGPacketLoss); childSetActionTextbox("stat_btn", onClickStatGraph); - } LLStatusBar::~LLStatusBar() @@ -244,7 +245,6 @@ BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask) BOOL LLStatusBar::postBuild() { - gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3)); return TRUE; @@ -506,6 +506,13 @@ static void onClickScriptDebug(void*) LLFloaterScriptDebug::show(LLUUID::null); } +//static +void LLStatusBar::onMouseEnterVolume(LLUICtrl* ctrl) +{ + // show the master volume pull-down + LLFloaterReg::showInstance("volume_pulldown"); +} + static void onClickVolume(void* data) { // toggle the master mute setting diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index bdaacce981..f77cc1acb8 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -47,6 +47,7 @@ class LLUICtrl; class LLUUID; class LLFrameTimer; class LLStatGraph; +class LLPanelVolumePulldown; class LLStatusBar : public LLPanel @@ -92,8 +93,8 @@ private: void onVolumeChanged(const LLSD& newvalue); + static void onMouseEnterVolume(LLUICtrl* ctrl); static void onClickStatGraph(void* data); - private: LLTextBox *mTextHealth; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 642df92379..1a8edb1f6a 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -38,6 +38,7 @@ #include "llviewerfloaterreg.h" #include "llcompilequeue.h" +#include "llcallfloater.h" #include "llfloaterabout.h" #include "llfloateractivespeakers.h" #include "llfloateranimpreview.h" @@ -105,6 +106,7 @@ #include "llfloateruipreview.h" #include "llfloaterurldisplay.h" #include "llfloatervoicedevicesettings.h" +#include "llfloatervolumepulldown.h" #include "llfloaterwater.h" #include "llfloaterwhitelistentry.h" #include "llfloaterwindlight.h" @@ -174,7 +176,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>); - LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>); LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); @@ -234,6 +235,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); + LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>); LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); @@ -247,7 +249,9 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); + LLFloaterReg::add("volume_pulldown", "floater_volume_pulldown.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVolumePulldown>); LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCall>); + LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>); LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 639585de55..fe0114d687 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -52,7 +52,7 @@ public: STATE_CONNECTED } EState; - typedef boost::function<void(const EState& old_state, const EState& new_state)> state_changed_callback_t; + typedef boost::signals2::signal<void(const EState& old_state, const EState& new_state)> state_changed_signal_t; // on current channel changed signal typedef boost::function<void(const LLUUID& session_id)> channel_changed_callback_t; @@ -78,7 +78,8 @@ public: virtual BOOL callStarted(); const std::string& getSessionName() const { return mSessionName; } - void setStateChangedCallback(state_changed_callback_t callback) { mStateChangedCallback = callback; } + boost::signals2::connection setStateChangedCallback(const state_changed_signal_t::slot_type& callback) + { return mStateChangedCallback.connect(callback); } const LLUUID getSessionID() { return mSessionID; } EState getState() { return mState; } @@ -124,7 +125,7 @@ protected: static BOOL sSuspended; private: - state_changed_callback_t mStateChangedCallback; + state_changed_signal_t mStateChangedCallback; }; class LLVoiceChannelGroup : public LLVoiceChannel @@ -175,6 +176,9 @@ public: void setSessionHandle(const std::string& handle, const std::string &inURI); + // returns TRUE if call is incoming and FALSE otherwise + BOOL isIncomingCall() { return mReceivedCall; } + protected: virtual void setState(EState state); diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index eb8ec00bb9..295f4259fd 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -81,7 +81,7 @@ <color name="AgentChatColor" - reference="LtGray" /> + reference="White" /> <color name="AlertBoxColor" value="0.24 0.24 0.24 1" /> @@ -669,7 +669,7 @@ reference="LtGray" /> <color name="UserChatColor" - reference="LtGray" /> + reference="White" /> <color name="llOwnerSayChatColor" reference="LtGray" /> @@ -684,5 +684,8 @@ <color name="SysWellItemSelected" value="0.3 0.3 0.3 1.0" /> + <color + name="ChatToastAgentNameColor" + value="1.0 0.3 1.0 1.0" /> </colors> diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml index 69f9f6a2f8..d378b427f1 100644 --- a/indra/newview/skins/default/xui/en/floater_camera.xml +++ b/indra/newview/skins/default/xui/en/floater_camera.xml @@ -12,6 +12,7 @@ help_topic="camera_floater" save_rect="true" save_visibility="true" + single_instance="true" width="150"> <floater.string name="rotate_tooltip"> diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml new file mode 100644 index 0000000000..4434fe7403 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_resize="true" + height="300" + layout="topleft" + name="floater_voice_controls" + title="Voice Controls" + save_visibility="true" + single_instance="true" + width="282"> + <panel + bevel_style="in" + follows="left|right|top" + height="73" + layout="topleft" + left="0" + name="control_panel" + width="285"> + <panel + height="20" + layout="topleft" + left="10" + name="my_panel" + width="262"> + <avatar_icon + enabled="false" + follows="left|top" + height="18" + image_name="Generic_Person" + layout="topleft" + left="0" + name="user_icon" + top="0" + width="18" /> + <text + follows="top|left" + font="SansSerifSmallBold" + height="16" + layout="topleft" + left_pad="10" + name="user_text" + text_color="white" + top="4" + value="Mya Avatar:" + width="80" /> + </panel> + <layout_stack + bottom="10" + clip="false" + follows="left|right|top" + height="24" + layout="bottomleft" + orientation="horizontal" + width="262"> + <layout_panel + follows="left" + layout="topleft" + min_width="24" + top="0" + user_resize="false" + width="24"> + <icon + height="24" + image_name="Microphone_On" + layout="topleft" + name="Microphone_On" + top="0" + width="24" /> + </layout_panel> + <layout_panel + layout="topleft" + top="0" + user_resize="false" + width="258"> + <slider_bar + control_name="AudioLevelMic" + follows="left|right|top" + height="24" + increment="0.05" + layout="topleft" + left="0" + max_val="2" + name="volume_slider_bar" + tool_tip="Master Volume" + top="0" + value="0.75" + width="258" /> + </layout_panel> + </layout_stack> + </panel> + <avatar_list + follows="all" + height="197" + ignore_online_status="true" + layout="topleft" + left="0" + multi_select="true" + name="speakers_list" + width="282" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6e178ad570..49276172d5 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1172,6 +1172,13 @@ Eject [AVATAR_NAME] from your land? <notification icon="alertmodal.tga" + name="EjectAvatarFromGroup" + type="notify"> +You ejected [AVATAR_NAME] from group [GROUP_NAME] + </notification> + + <notification + icon="alertmodal.tga" name="AcquireErrorTooManyObjects" type="alertmodal"> ACQUIRE ERROR: Too many objects selected. @@ -2375,15 +2382,15 @@ Please choose the male or female avatar. You can change your mind later. <notification icon="alertmodal.tga" name="GrantedModifyRights" - type="alertmodal"> -[FIRST_NAME] [LAST_NAME] has given you permission to edit their objects. + type="notify"> +[NAME] has given you permission to edit their objects. </notification> <notification icon="alertmodal.tga" name="RevokedModifyRights" - type="alertmodal"> -Your privilege to modify [FIRST_NAME] [LAST_NAME]'s objects has been revoked + type="notify"> +Your privilege to modify [NAME]'s objects has been revoked </notification> <notification diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml index 368ab17689..f5fce65c73 100644 --- a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml @@ -48,7 +48,6 @@ visible="false" width="100" /> <button - enabled="false" follows="all" bottom="10" height="20" diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml index 2eaa3a94ee..45f9d9c7b6 100644 --- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml @@ -7,6 +7,18 @@ name="avatar_list_item" top="0" width="320"> + <!-- + Strings used to localize last interaction time. + See last_interaction textbox below. + --> + <string name="FormatSeconds">[COUNT]s</string> + <string name="FormatMinutes">[COUNT]m</string> + <string name="FormatHours">[COUNT]h</string> + <string name="FormatDays">[COUNT]d</string> + <string name="FormatWeeks">[COUNT]w</string> + <string name="FormatMonths">[COUNT]mon</string> + <string name="FormatYears">[COUNT]y</string> + <icon follows="top|right|left" height="24" diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index da8006d545..ec3f7ea7c5 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -72,7 +72,13 @@ left="0" name="talk" top="4" - width="100" /> + width="100"> + <show_button> + <show_button.init_callback + function="Button.SetDockableFloaterToggle" + parameter="voice_controls" /> + </show_button> + </talk_button> </layout_panel> <icon auto_resize="false" diff --git a/indra/newview/skins/default/xui/en/panel_chat_item.xml b/indra/newview/skins/default/xui/en/panel_chat_item.xml index 2b29796f0a..34c6e02684 100644 --- a/indra/newview/skins/default/xui/en/panel_chat_item.xml +++ b/indra/newview/skins/default/xui/en/panel_chat_item.xml @@ -2,70 +2,26 @@ <!-- All our XML is utf-8 encoded. --> <panel name="instant_message" - width="300" + width="315" height="180" follows="all"> - <panel - width="290" - height="24" - background_visible="true" - background_opaque="false" - bg_alpha_color="Black" - left="5" - name="msg_caption"> - <avatar_icon - follows="left" - height="18" - image_name="Generic_Person" - layout="topleft" - left="3" - mouse_opaque="true" - name="avatar_icon" - top="3" - width="18" /> - <text - font.style="BOLD" - height="12" - layout="topleft" - left_pad="5" - top="7" - text_color="white" - word_wrap="false" - use_ellipses="true" - mouse_opaque="true" - name="sender_name" - width="150"> - Jerry Knight - </text> - <!-- <icon top="22" left="215" width="15" height="15" follows="top|right" - image_name="icn_voice-pvtfocus.tga" visible="false" name="msg_inspector" />--> - <!--<icon top="22" left="215" width="10" height="10" follows="top|right" - image_name="speaking_indicator.tga" name="msg_icon"/>--> - <text - font="SansSerifSmall" - follows="right|top" - halign="right" - height="13" - layout="topleft" - right="-10" - left="205" - mouse_opaque="true" - name="msg_time" - top="8" - value="23:30" - width="50" - word_wrap="true" /> - </panel> + <avatar_icon + follows="left|top" + height="18" + image_name="Generic_Person" + layout="topleft" + left="3" + mouse_opaque="true" + name="avatar_icon" + top="3" + width="18" /> <text_chat - top="-35" - left="10" - right="-10" + top="5" + left="30" height="120" - follows="left|right|bottom" text_color="white" word_wrap="true" mouse_opaque="true" name="msg_text"> - To be or not to be, that is the question. Tis a far far better thing I do than I have ever done. Tis a far far better place I go, than I have ever been. </text_chat> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml index 41b210557e..889f29fc53 100644 --- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml @@ -61,7 +61,6 @@ width="125"/> <button - enabled="false" bottom="10" follows="all" height="20" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index bf33b752d9..9702bd41c8 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -153,7 +153,7 @@ layout="topleft" left="0" name="favorite" - image_drag_indication="Arrow_Down" + image_drag_indication="arrow_down.tga" chevron_button_tool_tip="Show more of My Favorites" bottom="62" width="590" /> diff --git a/indra/newview/skins/default/xui/en/panel_picks.xml b/indra/newview/skins/default/xui/en/panel_picks.xml index ca84c9147b..4f0d155876 100644 --- a/indra/newview/skins/default/xui/en/panel_picks.xml +++ b/indra/newview/skins/default/xui/en/panel_picks.xml @@ -27,6 +27,7 @@ There are no picks/classifieds here </text> <accordion + fit_parent="true" follows="all" height="465" layout="topleft" 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 65bc48265d..9c66653e3c 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -81,6 +81,17 @@ 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" follows="right|bottom" |