diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 7a970b1466..9920921a58 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -75,6 +75,10 @@ const int LL_ERR_PRICE_MISMATCH = -23018; #define SHOW_ASSERT #else // _DEBUG +#ifdef LL_RELEASE_WITH_DEBUG_INFO +#define SHOW_ASSERT +#endif // LL_RELEASE_WITH_DEBUG_INFO + #ifdef RELEASE_SHOW_DEBUG #define SHOW_DEBUG #endif diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index cd76bfe709..8af79c90fd 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,11 +1,11 @@ -/** +/** * @file llfasttimer.h * @brief Declaration of a fast timer. * * $LicenseInfo:firstyear=2004&license=viewergpl$ - * + * * Copyright (c) 2004-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 @@ -13,17 +13,17 @@ * ("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. @@ -69,7 +69,7 @@ inline U32 get_cpu_clock_count_32() { U32 ret_val; - __asm + __asm { _emit 0x0f _emit 0x31 @@ -85,7 +85,7 @@ inline U32 get_cpu_clock_count_32() inline U64 get_cpu_clock_count_64() { U64 ret_val; - __asm + __asm { _emit 0x0f _emit 0x31 @@ -99,21 +99,21 @@ inline U64 get_cpu_clock_count_64() #else #define LL_INLINE #endif - -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) -inline U32 get_cpu_clock_count_32() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return (U32)x >> 8; -} - -inline U32 get_cpu_clock_count_64() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return x >> 8; -} + +#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +inline U32 get_cpu_clock_count_32() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return (U32)x >> 8; +} + +inline U32 get_cpu_clock_count_64() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return x >> 8; +} #endif #if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) @@ -128,7 +128,7 @@ inline U32 get_cpu_clock_count_32() } inline U32 get_cpu_clock_count_64() -{ +{ return get_clock_count(); } #endif @@ -158,7 +158,7 @@ public: }; // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances - class LL_COMMON_API NamedTimer + class LL_COMMON_API NamedTimer : public LLInstanceTracker { friend class DeclareTimer; @@ -193,7 +193,7 @@ public: FrameState& getFrameState() const; - private: + private: friend class LLFastTimer; friend class NamedTimerFactory; @@ -204,14 +204,14 @@ public: // recursive call to gather total time from children static void accumulateTimings(); - // updates cumulative times and hierarchy, + // updates cumulative times and hierarchy, // can be called multiple times in a frame, at any point static void processTimes(); static void buildHierarchy(); static void resetFrame(); static void reset(); - + // // members // @@ -247,7 +247,7 @@ public: private: NamedTimer& mTimer; - FrameState* mFrameState; + FrameState* mFrameState; }; public: @@ -267,7 +267,7 @@ public: frame_state->mCalls++; // keep current parent as long as it is active when we are frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - + LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; mLastTimerData = *cur_timer_data; cur_timer_data->mCurTimer = this; @@ -305,7 +305,7 @@ public: U64 timer_end = get_cpu_clock_count_64(); sTimerCycles += timer_end - timer_start; sTimerCalls++; -#endif +#endif } public: @@ -321,13 +321,13 @@ public: typedef std::vector info_list_t; static info_list_t& getFrameStateList(); - + // call this once a frame to reset timers static void nextFrame(); // dumps current cumulative frame stats to log // call nextFrame() to reset timers - static void dumpCurTimes(); + static void dumpCurTimes(); // call this to reset timer hierarchy, averages, etc. static void reset(); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index d873005fd9..cd493481d5 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1736,12 +1736,25 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) if (u < 0.f || u > 1.f || v < 0.f || v > 1.f) { - llerrs << "WTF?" << llendl; + LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; + u = v = 0.f; + llassert(false); } S32 x = (S32)(u * width); S32 y = (S32)(v * height); + if (x >= width) + { + LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; + x = llmax(0, width-1); + } + if (y >= height) + { + LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; + y = llmax(0, height-1); + } + S32 idx = y*width+x; S32 offset = idx%8; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index e9f6288f44..9ce8ce8d55 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -1022,6 +1022,20 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a } } +void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color) +{ + if (image_id.isNull()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImageByID(image_id); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } +} + void LLButton::onMouseCaptureLost() { resetMouseDownTimer(); diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 5e28b8cdff..cd149e3113 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -200,6 +200,7 @@ public: void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); + void setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); LLPointer getImageOverlay() { return mImageOverlay; } void autoResize(); // resize with label of current btn state diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 4f519afa06..79d8f90fec 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1360,6 +1360,7 @@ void LLFloater::bringToFront( S32 x, S32 y ) // virtual void LLFloater::setVisibleAndFrontmost(BOOL take_focus) { + gFocusMgr.setTopCtrl(NULL); setVisible(TRUE); setFrontmost(take_focus); } diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 327dd01612..43c44f2253 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1507,6 +1507,37 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L } } +void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color) +{ + static LLUICachedControl tab_padding ("UITabPadding", 0); + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_id, LLFontGL::RIGHT, color); + + if (!mIsVertical) + { + // remove current width from total tab strip width + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + + S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : + 0; + + tuple->mPadding = image_overlay_width; + + tuple->mButton->setRightHPad(6); + tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), + tuple->mButton->getRect().getHeight()); + // add back in button width to total tab strip width + mTotalTabWidth += tuple->mButton->getRect().getWidth(); + + // tabs have changed size, might need to scroll to see current tab + updateMaxScrollPos(); + } + } +} + void LLTabContainer::setTitle(const std::string& title) { if (mTitleBox) diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 5d0f194bf9..33c49e0d6f 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -172,6 +172,7 @@ public: BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); + void setTabImage(LLPanel* child, const LLUUID& img_id, const LLColor4& color = LLColor4::white); void setTitle( const std::string& title ); const std::string getPanelTitle(S32 index); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ccafbae156..05f1e71711 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1145,17 +1145,6 @@ Value 5 - CallFloaterMaxItems - - Comment - Max number of visible participants in voice controls window - Persist - 1 - Type - S32 - Value - 5 - CameraAngle Comment @@ -3651,7 +3640,7 @@ Type String Value - http://int.searchwww-phx0.damballah.lindenlab.com/viewer/[CATEGORY]?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID] + http://search.secondlife.com/viewer/[CATEGORY]?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID] HighResSnapshot @@ -10114,6 +10103,18 @@ Value 1 + SpeakerParticipantRemoveDelay + + Comment + Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat) + Persist + 1 + Type + F32 + Value + 10.0 + + UseStartScreen Comment diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 748d8bdfbf..61d60fdff9 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -274,6 +274,7 @@ private: struct LLFoundData { + LLFoundData() {} LLFoundData(const LLUUID& item_id, const LLUUID& asset_id, const std::string& name, @@ -292,20 +293,94 @@ struct LLFoundData }; -struct LLWearableHoldingPattern +class LLWearableHoldingPattern { - LLWearableHoldingPattern() : mResolved(0) {} - ~LLWearableHoldingPattern() - { - for_each(mFoundList.begin(), mFoundList.end(), DeletePointer()); - mFoundList.clear(); - } - typedef std::list found_list_t; +public: + LLWearableHoldingPattern(); + ~LLWearableHoldingPattern(); + + bool pollCompletion(); + bool isDone(); + bool isTimedOut(); + + typedef std::list found_list_t; found_list_t mFoundList; + LLInventoryModel::item_array_t mObjItems; + LLInventoryModel::item_array_t mGestItems; S32 mResolved; - bool append; + LLTimer mWaitTime; }; +LLWearableHoldingPattern::LLWearableHoldingPattern(): + mResolved(0) +{ +} + +LLWearableHoldingPattern::~LLWearableHoldingPattern() +{ +} + +bool LLWearableHoldingPattern::isDone() +{ + if (mResolved >= (S32)mFoundList.size()) + return true; // have everything we were waiting for + else if (isTimedOut()) + { + llwarns << "Exceeded max wait time, updating appearance based on what has arrived" << llendl; + return true; + } + return false; + +} + +bool LLWearableHoldingPattern::isTimedOut() +{ + static F32 max_wait_time = 15.0; // give up if wearable fetches haven't completed in max_wait_time seconds. + return mWaitTime.getElapsedTimeF32() > max_wait_time; +} + +bool LLWearableHoldingPattern::pollCompletion() +{ + bool done = isDone(); + llinfos << "polling, done status: " << done << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + if (done) + { + // Activate all gestures in this folder + if (mGestItems.count() > 0) + { + llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; + + LLGestureManager::instance().activateGestures(mGestItems); + + // Update the inventory item labels to reflect the fact + // they are active. + LLViewerInventoryCategory* catp = + gInventory.getCategory(LLAppearanceManager::instance().getCOF()); + + if (catp) + { + gInventory.updateCategory(catp); + gInventory.notifyObservers(); + } + } + + // Update wearables. + llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; + LLAppearanceManager::instance().updateAgentWearables(this, false); + + // Update attachments to match those requested. + LLVOAvatar* avatar = gAgent.getAvatarObject(); + if( avatar ) + { + llinfos << "Updating " << mObjItems.count() << " attachments" << llendl; + LLAgentWearables::userUpdateAttachments(mObjItems); + } + + delete this; + } + return done; +} + static void removeDuplicateItems(LLInventoryModel::item_array_t& items) { LLInventoryModel::item_array_t new_items; @@ -336,26 +411,21 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) static void onWearableAssetFetch(LLWearable* wearable, void* data) { LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; - bool append = holder->append; if(wearable) { for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); iter != holder->mFoundList.end(); ++iter) { - LLFoundData* data = *iter; - if(wearable->getAssetID() == data->mAssetID) + LLFoundData& data = *iter; + if(wearable->getAssetID() == data.mAssetID) { - data->mWearable = wearable; + data.mWearable = wearable; break; } } } holder->mResolved += 1; - if(holder->mResolved >= (S32)holder->mFoundList.size()) - { - LLAppearanceManager::instance().updateAgentWearables(holder, append); - } } LLUUID LLAppearanceManager::getCOF() @@ -662,12 +732,12 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); iter != holder->mFoundList.end(); ++iter) { - LLFoundData* data = *iter; - LLWearable* wearable = data->mWearable; + LLFoundData& data = *iter; + LLWearable* wearable = data.mWearable; if( wearable && ((S32)wearable->getType() == i) ) { LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID); + item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { items.put(item); @@ -683,8 +753,6 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, gAgentWearables.setWearableOutfit(items, wearables, !append); } - delete holder; - // dec_busy_count(); } @@ -706,86 +774,66 @@ void LLAppearanceManager::updateAppearanceFromCOF() LLInventoryModel::item_array_t gest_items; getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); - if( !wear_items.count() && !obj_items.count() && !gest_items.count()) + if(!wear_items.count()) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); return; } + + LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; + + holder->mObjItems = obj_items; + holder->mGestItems = gest_items; - // Processes that take time should show the busy cursor - //inc_busy_count(); // BAP this is currently a no-op in llinventorybridge.cpp - do we need it? - - // Activate all gestures in this folder - if (gest_items.count() > 0) + // Note: can't do normal iteration, because if all the + // wearables can be resolved immediately, then the + // callback will be called (and this object deleted) + // before the final getNextData(). + LLDynamicArray found_container; + for(S32 i = 0; i < wear_items.count(); ++i) { - llinfos << "Activating " << gest_items.count() << " gestures" << llendl; - - LLGestureManager::instance().activateGestures(gest_items); - - // Update the inventory item labels to reflect the fact - // they are active. - LLViewerInventoryCategory* catp = gInventory.getCategory(current_outfit_id); - if (catp) + LLViewerInventoryItem *item = wear_items.get(i); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; + if (item && linked_item) { - gInventory.updateCategory(catp); - gInventory.notifyObservers(); + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType()); + holder->mFoundList.push_front(found); + found_container.put(found); + } + else + { + if (!item) + { + llwarns << "attempt to wear a null item " << llendl; + } + else if (!linked_item) + { + llwarns << "attempt to wear a broken link " << item->getName() << llendl; + } } } - if(wear_items.count() > 0) + for(S32 i = 0; i < found_container.count(); ++i) { - // Note: can't do normal iteration, because if all the - // wearables can be resolved immediately, then the - // callback will be called (and this object deleted) - // before the final getNextData(). - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - LLFoundData* found; - LLDynamicArray found_container; - for(S32 i = 0; i < wear_items.count(); ++i) - { - LLViewerInventoryItem *item = wear_items.get(i); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - if (item && linked_item) - { - found = new LLFoundData(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType()); - holder->mFoundList.push_front(found); - found_container.put(found); - } - else - { - if (!item) - { - llwarns << "attempt to wear a null item " << llendl; - } - else if (!linked_item) - { - llwarns << "attempt to wear a broken link " << item->getName() << llendl; - } - } - } - for(S32 i = 0; i < found_container.count(); ++i) - { - holder->append = false; - found = found_container.get(i); + LLFoundData& found = found_container.get(i); - // Fetch the wearables about to be worn. - LLWearableList::instance().getAsset(found->mAssetID, - found->mName, - found->mAssetType, - onWearableAssetFetch, - (void*)holder); - } + // Fetch the wearables about to be worn. + LLWearableList::instance().getAsset(found.mAssetID, + found.mName, + found.mAssetType, + onWearableAssetFetch, + (void*)holder); + } - // Update attachments to match those requested. - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( avatar ) + if (!holder->pollCompletion()) { - LLAgentWearables::userUpdateAttachments(obj_items); + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollCompletion,holder)); } + } void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category, diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 20745b70e4..517face777 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -39,7 +39,7 @@ #include "llcallbacklist.h" class LLWearable; -struct LLWearableHoldingPattern; +class LLWearableHoldingPattern; class LLAppearanceManager: public LLSingleton { @@ -168,4 +168,40 @@ void doOnIdle(T callable) gIdleCallbacks.addFunction(&OnIdleCallback::onIdle,cb_functor); } +// Shim class and template function to allow arbitrary boost::bind +// expressions to be run as recurring idle callbacks. +template +class OnIdleCallbackRepeating +{ +public: + OnIdleCallbackRepeating(T callable): + mCallable(callable) + { + } + // Will keep getting called until the callable returns false. + static void onIdle(void *data) + { + OnIdleCallbackRepeating* self = reinterpret_cast*>(data); + bool done = self->call(); + if (done) + { + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; + } + } + bool call() + { + return mCallable(); + } +private: + T mCallable; +}; + +template +void doOnIdleRepeating(T callable) +{ + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); +} + #endif diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6d0bbee755..d38278864b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -907,7 +907,6 @@ bool LLAppViewer::mainLoop() { LLMemType mt1(LLMemType::MTYPE_MAIN); mMainloopTimeout = new LLWatchdogTimeout(); - // *FIX:Mani - Make this a setting, once new settings exist in this branch. //------------------------------------------- // Run main loop until time to quit @@ -917,11 +916,11 @@ bool LLAppViewer::mainLoop() gServicePump = new LLPumpIO(gAPRPoolp); LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); - + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. + LLVoiceChannel::initClass(); LLVoiceClient::getInstance()->init(gServicePump); - LLTimer frameTimer,idleTimer; LLTimer debugTime; LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 38edbd04ba..ae081882f8 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -263,18 +263,9 @@ bool LLAvatarActions::isCalling(const LLUUID &id) } //static -bool LLAvatarActions::canCall(const LLUUID &id) +bool LLAvatarActions::canCall() { - // For now we do not need to check whether passed UUID is ID of agent's friend. - // Use common check of Voice Client state. - { - // don't need to check online/offline status because "usual resident" (resident that is not a friend) - // can be only ONLINE. There is no way to see "usual resident" in OFFLINE status. If we see "usual - // resident" it automatically means that the resident is ONLINE. So to make a call to the "usual resident" - // we need to check only that "our" voice is enabled. - return LLVoiceClient::getInstance()->voiceEnabled(); - } - + return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); } // static diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index a4504ae679..ebfd40b796 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -129,10 +129,10 @@ public: static bool isCalling(const LLUUID &id); /** - * @return true if call to the resident can be made (resident is online and voice is enabled) + * @return true if call to the resident can be made */ - static bool canCall(const LLUUID &id); + static bool canCall(); /** * Invite avatar to a group. */ diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index 66ab32f3e8..2bcd097717 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -440,17 +440,17 @@ LLAvatarListItem::icon_color_map_t& LLAvatarListItem::getItemIconColorMap() // static void LLAvatarListItem::initChildrenWidths(LLAvatarListItem* avatar_item) { + //speaking indicator width + padding + S32 speaking_indicator_width = avatar_item->getRect().getWidth() - avatar_item->mSpeakingIndicator->getRect().mLeft; + //profile btn width + padding - S32 profile_btn_width = avatar_item->getRect().getWidth() - avatar_item->mProfileBtn->getRect().mLeft; + S32 profile_btn_width = avatar_item->mSpeakingIndicator->getRect().mLeft - avatar_item->mProfileBtn->getRect().mLeft; //info btn width + padding S32 info_btn_width = avatar_item->mProfileBtn->getRect().mLeft - avatar_item->mInfoBtn->getRect().mLeft; - //speaking indicator width + padding - S32 speaking_indicator_width = avatar_item->mInfoBtn->getRect().mLeft - avatar_item->mSpeakingIndicator->getRect().mLeft; - // last interaction time textbox width + padding - S32 last_interaction_time_width = avatar_item->mSpeakingIndicator->getRect().mLeft - avatar_item->mLastInteractionTime->getRect().mLeft; + S32 last_interaction_time_width = avatar_item->mInfoBtn->getRect().mLeft - avatar_item->mLastInteractionTime->getRect().mLeft; // icon width + padding S32 icon_width = avatar_item->mAvatarName->getRect().mLeft - avatar_item->mAvatarIcon->getRect().mLeft; @@ -462,9 +462,9 @@ void LLAvatarListItem::initChildrenWidths(LLAvatarListItem* avatar_item) sChildrenWidths[--index] = icon_width; sChildrenWidths[--index] = 0; // for avatar name we don't need its width, it will be calculated as "left available space" sChildrenWidths[--index] = last_interaction_time_width; - sChildrenWidths[--index] = speaking_indicator_width; sChildrenWidths[--index] = info_btn_width; sChildrenWidths[--index] = profile_btn_width; + sChildrenWidths[--index] = speaking_indicator_width; } void LLAvatarListItem::updateChildren() diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 479a4833cb..61c0a8660e 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -129,9 +129,9 @@ private: * @see updateChildren() */ typedef enum e_avatar_item_child { + ALIC_SPEAKER_INDICATOR, ALIC_PROFILE_BUTTON, ALIC_INFO_BUTTON, - ALIC_SPEAKER_INDICATOR, ALIC_INTERACTION_TIME, ALIC_NAME, ALIC_ICON, diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index aa45f9328d..0509d4f619 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -322,7 +322,7 @@ void LLBottomTray::setVisible(BOOL visible) // Chat bar and gesture button are shown even in mouselook mode. // But the move, camera and snapshot buttons shouldn't be displayed. See EXT-3988. - if ("chat_bar" == name || "gesture_panel" == name) + if ("chat_bar" == name || "gesture_panel" == name || (visibility && ("movement_panel" == name || "cam_panel" == name || "snapshot_panel" == name))) continue; else { diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 21496aaa89..289b4d1542 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -51,7 +51,6 @@ #include "lltransientfloatermgr.h" #include "llviewerwindow.h" #include "llvoicechannel.h" -#include "lllayoutstack.h" static void get_voice_participants_uuids(std::vector& speakers_uuids); void reshape_floater(LLCallFloater* floater, S32 delta_height); @@ -94,22 +93,6 @@ static void* create_non_avatar_caller(void*) return new LLNonAvatarCaller; } -LLCallFloater::LLAvatarListItemRemoveTimer::LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id) -: LLEventTimer(period) -, mRemoveCallback(remove_cb) -, mSpeakerId(speaker_id) -{ -} - -BOOL LLCallFloater::LLAvatarListItemRemoveTimer::tick() -{ - if (mRemoveCallback) - { - mRemoveCallback(mSpeakerId); - } - return TRUE; -} - LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL; LLCallFloater::LLCallFloater(const LLSD& key) @@ -123,10 +106,9 @@ LLCallFloater::LLCallFloater(const LLSD& key) , mSpeakingIndicator(NULL) , mIsModeratorMutedVoice(false) , mInitParticipantsVoiceState(false) -, mVoiceLeftRemoveDelay(10) { static LLUICachedControl voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10); - mVoiceLeftRemoveDelay = voice_left_remove_delay; + mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay); mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL); LLVoiceClient::getInstance()->addObserver(this); @@ -136,6 +118,7 @@ LLCallFloater::LLCallFloater(const LLSD& key) LLCallFloater::~LLCallFloater() { resetVoiceRemoveTimers(); + delete mSpeakerDelayRemover; delete mParticipants; mParticipants = NULL; @@ -225,16 +208,6 @@ void LLCallFloater::onChange() } } -S32 LLCallFloater::notifyParent(const LLSD& info) -{ - if("size_changes" == info["action"]) - { - reshapeToFitContent(); - return 1; - } - return LLDockableFloater::notifyParent(info); -} - ////////////////////////////////////////////////////////////////////////// /// PRIVATE SECTION ////////////////////////////////////////////////////////////////////////// @@ -315,32 +288,7 @@ void LLCallFloater::updateSession() //hide "Leave Call" button for nearby chat bool is_local_chat = mVoiceType == VC_LOCAL_CHAT; - - LLPanel* leave_panel = findChild("leave_call_btn_panel"); - if (leave_panel) - { - S32 delta = 0; - bool visible = !is_local_chat; - if ((bool)leave_panel->getVisible() != visible) - { - delta = visible - ? leave_panel->getRect().getHeight() - : -leave_panel->getRect().getHeight(); - } - leave_panel->setVisible(visible); - if (delta) - { - LLLayoutStack* stack = getChild("my_call_stack"); - BOOL animate = stack->getAnimate(); - // Disable animation to prevent layout updating in several frames. - // We need this to get work reshapeToFitContent properly, otherwise - // the height of leave_call_btn_panel won't be completely included. - stack->setAnimate(FALSE); - reshape_floater(this, delta); - // Restore animate state. - stack->setAnimate(animate); - } - } + childSetVisible("leave_call_btn_panel", !is_local_chat); refreshParticipantList(); updateAgentModeratorState(); @@ -682,33 +630,11 @@ void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state) void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id) { - - // If there is already a started timer for the current panel don't do anything. - bool no_timer_for_current_panel = true; - if (mVoiceLeftTimersMap.size() > 0) - { - timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); - if (found_it != mVoiceLeftTimersMap.end()) - { - no_timer_for_current_panel = false; - } - } - - if (no_timer_for_current_panel) - { - // Starting a timer to remove an avatar row panel after timeout - mVoiceLeftTimersMap.insert(timer_pair(voice_speaker_id, - new LLAvatarListItemRemoveTimer(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), mVoiceLeftRemoveDelay, voice_speaker_id))); - } + mSpeakerDelayRemover->setActionTimer(voice_speaker_id); } -void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id) +bool LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id) { - if (mVoiceLeftTimersMap.size() > 0) - { - mVoiceLeftTimersMap.erase(mVoiceLeftTimersMap.find(voice_speaker_id)); - } - LLAvatarList::uuid_vector_t& speaker_uuids = mAvatarList->getIDs(); LLAvatarList::uuid_vector_t::iterator pos = std::find(speaker_uuids.begin(), speaker_uuids.end(), voice_speaker_id); if(pos != speaker_uuids.end()) @@ -716,34 +642,19 @@ void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id) speaker_uuids.erase(pos); mAvatarList->setDirty(); } + + return false; } void LLCallFloater::resetVoiceRemoveTimers() { - if (mVoiceLeftTimersMap.size() > 0) - { - for (timers_map::iterator iter = mVoiceLeftTimersMap.begin(); - iter != mVoiceLeftTimersMap.end(); ++iter) - { - delete iter->second; - } - } - mVoiceLeftTimersMap.clear(); + mSpeakerDelayRemover->removeAllTimers(); } void LLCallFloater::removeVoiceRemoveTimer(const LLUUID& voice_speaker_id) { - // Remove the timer if it has been already started - if (mVoiceLeftTimersMap.size() > 0) - { - timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); - if (found_it != mVoiceLeftTimersMap.end()) - { - delete found_it->second; - mVoiceLeftTimersMap.erase(found_it); - } - } + mSpeakerDelayRemover->unsetActionTimer(voice_speaker_id); } bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id) @@ -822,90 +733,4 @@ void LLCallFloater::reset() mSpeakerManager = NULL; } -void reshape_floater(LLCallFloater* floater, S32 delta_height) -{ - // Try to update floater top side if it is docked(to bottom bar). - // Try to update floater bottom side or top side if it is un-docked. - // If world rect is too small, floater will not be reshaped at all. - - LLRect floater_rect = floater->getRect(); - LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); - - // floater is docked to bottom bar - if(floater->isDocked()) - { - // can update floater top side - if(floater_rect.mTop + delta_height < world_rect.mTop) - { - floater_rect.set(floater_rect.mLeft, floater_rect.mTop + delta_height, - floater_rect.mRight, floater_rect.mBottom); - } - } - // floater is un-docked - else - { - // can update floater bottom side - if( floater_rect.mBottom - delta_height >= world_rect.mBottom ) - { - floater_rect.set(floater_rect.mLeft, floater_rect.mTop, - floater_rect.mRight, floater_rect.mBottom - delta_height); - } - // could not update floater bottom side, check if we can update floater top side - else if( floater_rect.mTop + delta_height < world_rect.mTop ) - { - floater_rect.set(floater_rect.mLeft, floater_rect.mTop + delta_height, - floater_rect.mRight, floater_rect.mBottom); - } - } - - floater->setShape(floater_rect); - floater->getChild("my_call_stack")->updateLayout(FALSE); -} - -void LLCallFloater::reshapeToFitContent() -{ - const S32 ITEM_HEIGHT = getParticipantItemHeight(); - static const S32 MAX_VISIBLE_ITEMS = getMaxVisibleItems(); - - static S32 items_pad = mAvatarList->getItemsPad(); - S32 list_height = mAvatarList->getRect().getHeight(); - S32 items_height = mAvatarList->getItemsRect().getHeight(); - if(items_height <= 0) - { - // make "no one near" text visible - items_height = ITEM_HEIGHT + items_pad; - } - S32 max_list_height = MAX_VISIBLE_ITEMS * ITEM_HEIGHT + items_pad * (MAX_VISIBLE_ITEMS - 1); - max_list_height += 2* mAvatarList->getBorderWidth(); - - S32 delta = items_height - list_height; - // too many items, don't reshape floater anymore, let scroll bar appear. - if(items_height > max_list_height) - { - delta = max_list_height - list_height; - } - - reshape_floater(this, delta); -} - -S32 LLCallFloater::getParticipantItemHeight() -{ - std::vector items; - mAvatarList->getItems(items); - if(items.size() > 0) - { - return items[0]->getRect().getHeight(); - } - else - { - return getChild("non_avatar_caller")->getRect().getHeight(); - } -} - -S32 LLCallFloater::getMaxVisibleItems() -{ - static LLCachedControl max_visible_items(*LLUI::sSettingGroups["config"],"CallFloaterMaxItems"); - return max_visible_items; -} - //EOF diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 2b40225906..eded3a426b 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -44,6 +44,8 @@ class LLNonAvatarCaller; class LLOutputMonitorCtrl; class LLParticipantList; class LLSpeakerMgr; +class LLSpeakersDelayActionsStorage; + /** * 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. @@ -75,11 +77,6 @@ public: */ /*virtual*/ void onChange(); - /** - * Will reshape floater when participant list size changes - */ - /*virtual*/ S32 notifyParent(const LLSD& info); - static void sOnCurrentChannelChanged(const LLUUID& session_id); private: @@ -174,7 +171,7 @@ private: * * @param voice_speaker_id LLUUID of Avatar List item to be removed from the list. */ - void removeVoiceLeftParticipant(const LLUUID& voice_speaker_id); + bool removeVoiceLeftParticipant(const LLUUID& voice_speaker_id); /** * Deletes all timers from the list to prevent started timers from ticking after destruction @@ -221,21 +218,6 @@ private: */ void reset(); - /** - * Reshapes floater to fit participant list height - */ - void reshapeToFitContent(); - - /** - * Returns height of participant list item - */ - S32 getParticipantItemHeight(); - - /** - * Returns predefined max visible participants. - */ - S32 getMaxVisibleItems(); - private: speaker_state_map_t mSpeakerStateMap; LLSpeakerMgr* mSpeakerManager; @@ -260,32 +242,11 @@ private: boost::signals2::connection mAvatarListRefreshConnection; + /** - * class LLAvatarListItemRemoveTimer - * - * Implements a timer that removes avatar list item of a participant - * who has left the call. + * time out speakers when they are not part of current session */ - class LLAvatarListItemRemoveTimer : public LLEventTimer - { - public: - typedef boost::function callback_t; - - LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id); - virtual ~LLAvatarListItemRemoveTimer() {}; - - virtual BOOL tick(); - - private: - callback_t mRemoveCallback; - LLUUID mSpeakerId; - }; - - typedef std::pair timer_pair; - typedef std::map timers_map; - - timers_map mVoiceLeftTimersMap; - S32 mVoiceLeftRemoveDelay; + LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; /** * Stores reference to current voice channel. diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 8da207f887..f1de4e2982 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -1272,6 +1272,7 @@ bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 index) chiclet->setChicletSizeChangedCallback(boost::bind(&LLChicletPanel::onChicletSizeChanged, this, _1, index)); arrange(); + LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, chiclet); return true; } @@ -1299,6 +1300,7 @@ void LLChicletPanel::removeChiclet(chiclet_list_t::iterator it) mChicletList.erase(it); arrange(); + LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, chiclet); chiclet->die(); } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index fb94657278..0e42ff09d8 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -51,6 +51,7 @@ #include "llinventorymodel.h" #include "llfloaterworldmap.h" #include "lllandmarkactions.h" +#include "llnotificationsutil.h" #include "llsidetray.h" #include "lltoggleablemenu.h" #include "llviewerinventory.h" @@ -975,6 +976,10 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) void copy_slurl_to_clipboard_cb(std::string& slurl) { gClipboard.copyFromString(utf8str_to_wstring(slurl)); + + LLSD args; + args["SLURL"] = slurl; + LLNotificationsUtil::add("CopySLURL", args); } diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 29f415bd43..c71764c2e5 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -75,7 +75,7 @@ LLFloaterGroupPicker::~LLFloaterGroupPicker() void LLFloaterGroupPicker::setPowersMask(U64 powers_mask) { mPowersMask = powers_mask; - postBuild(); + init_group_list(getChild("group list"), gAgent.getGroupID(), mPowersMask); } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 3fd37c09dd..99ecd88dcb 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -277,13 +277,7 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) { object_owner.append("Unknown"); } - childSetText("object_name", object_owner); - std::string owner_link = - LLSLURL("agent", mObjectID, "inspect").getSLURLString(); - childSetText("owner_name", owner_link); - childSetText("abuser_name_edit", object_owner); - mAbuserID = object_id; - mOwnerName = object_owner; + setFromAvatar(object_id, object_owner); } else { @@ -305,7 +299,6 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) } } - void LLFloaterReporter::onClickSelectAbuser() { gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, this, _1, _2), FALSE, TRUE )); @@ -323,6 +316,18 @@ void LLFloaterReporter::callbackAvatarID(const std::vector& names, } +void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name) +{ + mAbuserID = mObjectID = avatar_id; + mOwnerName = avatar_name; + + std::string avatar_link = + LLSLURL("agent", mObjectID, "inspect").getSLURLString(); + childSetText("owner_name", avatar_link); + childSetText("object_name", avatar_name); + childSetText("abuser_name_edit", avatar_name); +} + // static void LLFloaterReporter::onClickSend(void *userdata) { @@ -458,9 +463,8 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) } } - // static -void LLFloaterReporter::showFromObject(const LLUUID& object_id) +void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name) { LLFloaterReporter* f = LLFloaterReg::showTypedInstance("reporter"); @@ -469,8 +473,11 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id) LLAgentUI::buildFullname(fullname); f->childSetText("reporter_field", fullname); - // Request info for this object - f->getObjectInfo(object_id); + if (avatar_name.empty()) + // Request info for this object + f->getObjectInfo(object_id); + else + f->setFromAvatar(object_id, avatar_name); // Need to deselect on close f->mDeselectOnClose = TRUE; @@ -479,6 +486,18 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id) } +// static +void LLFloaterReporter::showFromObject(const LLUUID& object_id) +{ + show(object_id); +} + +// static +void LLFloaterReporter::showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name) +{ + show(avatar_id, avatar_name); +} + void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id) { childSetText("object_name", object_name); diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index cc2dfb2f98..7c6473f975 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -93,6 +93,7 @@ public: static void showFromMenu(EReportType report_type); static void showFromObject(const LLUUID& object_id); + static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name); static void onClickSend (void *userdata); static void onClickCancel (void *userdata); @@ -109,6 +110,8 @@ public: void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id); private: + static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null); + void takeScreenshot(); void sendReportViaCaps(std::string url); void uploadImage(); @@ -121,6 +124,7 @@ private: void enableControls(BOOL own_avatar); void getObjectInfo(const LLUUID& object_id); void callbackAvatarID(const std::vector& names, const std::vector& ids); + void setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name = LLStringUtil::null); private: EReportType mReportType; diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index a63fb73032..b833c611bf 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1391,6 +1391,7 @@ void LLFolderView::startRenamingSelectedItem( void ) // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1)); + mRenamer->setFocusLostCallback(boost::bind(onRenamerLost, _1)); gFocusMgr.setTopCtrl( mRenamer ); } } diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index e75d35bea4..b8b9fe2742 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -48,6 +48,7 @@ #include "lltextutil.h" #include "llviewercontrol.h" // for gSavedSettings #include "llviewermenu.h" // for gMenuHolder +#include "llvoiceclient.h" static LLDefaultChildRegistry::Register r("group_list"); S32 LLGroupListItem::sIconWidth = 0; @@ -271,6 +272,9 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) if (userdata.asString() == "activate") return gAgent.getGroupID() != selected_group_id; + if (userdata.asString() == "call") + return LLVoiceClient::getInstance()->voiceEnabled()&&LLVoiceClient::getInstance()->isVoiceWorking(); + return real_group_selected; } diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 5dc7f900e7..a39753aa55 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -109,6 +109,8 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) } } setOverlapsScreenChannel(true); + + LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this); } void LLIMFloater::onFocusLost() @@ -227,6 +229,7 @@ void LLIMFloater::sendMsg() LLIMFloater::~LLIMFloater() { + LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this); } //virtual @@ -350,13 +353,15 @@ void* LLIMFloater::createPanelAdHocControl(void* userdata) void LLIMFloater::onSlide() { - LLPanel* im_control_panel = getChild("panel_im_control_panel"); - im_control_panel->setVisible(!im_control_panel->getVisible()); + mControlPanel->setVisible(!mControlPanel->getVisible()); - gSavedSettings.setBOOL("IMShowControlPanel", im_control_panel->getVisible()); + gSavedSettings.setBOOL("IMShowControlPanel", mControlPanel->getVisible()); - getChild("slide_left_btn")->setVisible(im_control_panel->getVisible()); - getChild("slide_right_btn")->setVisible(!im_control_panel->getVisible()); + getChild("slide_left_btn")->setVisible(mControlPanel->getVisible()); + getChild("slide_right_btn")->setVisible(!mControlPanel->getVisible()); + + LLLayoutStack* stack = getChild("im_panels"); + if (stack) stack->setAnimate(true); } //static @@ -510,14 +515,14 @@ bool LLIMFloater::toggle(const LLUUID& session_id) if(!isChatMultiTab()) { LLIMFloater* floater = LLFloaterReg::findTypedInstance("impanel", session_id); - if (floater && floater->getVisible()) + if (floater && floater->getVisible() && floater->hasFocus()) { // clicking on chiclet to close floater just hides it to maintain existing // scroll/text entry state floater->setVisible(false); return false; } - else if(floater && !floater->isDocked()) + else if(floater && (!floater->isDocked() || floater->getVisible() && !floater->hasFocus())) { floater->setVisible(TRUE); floater->setFocus(TRUE); diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index d9db385d06..0ca0325451 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -116,6 +116,8 @@ public: static void onIMChicletCreated(const LLUUID& session_id); + virtual LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; } + private: // process focus events to set a currently active session /* virtual */ void onFocusLost(); diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 6cc985aef4..06a7b4a29c 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -35,19 +35,22 @@ #include "llimfloatercontainer.h" #include "llfloaterreg.h" +#include "llimview.h" +#include "llavatariconctrl.h" +#include "llagent.h" // // LLIMFloaterContainer // LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) -: LLMultiFloater(seed), - mActiveVoiceFloater(NULL) +: LLMultiFloater(seed) { mAutoResize = FALSE; } LLIMFloaterContainer::~LLIMFloaterContainer() { + LLGroupMgr::getInstance()->removeObserver(this); } BOOL LLIMFloaterContainer::postBuild() @@ -87,11 +90,82 @@ void LLIMFloaterContainer::addFloater(LLFloater* floaterp, LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point); - // make sure active voice icon shows up for new tab - if (floaterp == mActiveVoiceFloater) + LLUUID session_id = floaterp->getKey(); + + if(gAgent.isInGroup(session_id)) { - mTabContainer->setTabImage(floaterp, "active_voice_tab.tga"); + mSessions[session_id] = floaterp; + mID = session_id; + mGroupID.push_back(session_id); + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(session_id); + LLGroupMgr* gm = LLGroupMgr::getInstance(); + gm->addObserver(this); + + if (group_data && group_data->mInsigniaID.notNull()) + { + mTabContainer->setTabImage(get_ptr_in_map(mSessions, session_id), group_data->mInsigniaID); + } + else + { + gm->sendGroupPropertiesRequest(session_id); + } } + else + { + LLUUID avatar_id = LLIMModel::getInstance()->getOtherParticipantID(session_id); + LLAvatarPropertiesProcessor& app = LLAvatarPropertiesProcessor::instance(); + app.addObserver(avatar_id, this); + floaterp->mCloseSignal.connect(boost::bind(&LLIMFloaterContainer::onCloseFloater, this, avatar_id)); + mSessions[avatar_id] = floaterp; + + LLUUID* icon_id_ptr = LLAvatarIconIDCache::getInstance()->get(avatar_id); + if(!icon_id_ptr) + { + app.sendAvatarPropertiesRequest(avatar_id); + } + else + { + mTabContainer->setTabImage(floaterp, *icon_id_ptr); + } + } +} + +void LLIMFloaterContainer::processProperties(void* data, enum EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast(data); + if (avatar_data) + { + LLUUID avatar_id = avatar_data->avatar_id; + if(avatar_data->image_id != *LLAvatarIconIDCache::getInstance()->get(avatar_id)) + { + LLAvatarIconIDCache::getInstance()->add(avatar_id,avatar_data->image_id); + } + mTabContainer->setTabImage(get_ptr_in_map(mSessions, avatar_id), avatar_data->image_id); + } + } +} + +void LLIMFloaterContainer::changed(LLGroupChange gc) +{ + if (GC_PROPERTIES == gc) + { + for(groupIDs_t::iterator it = mGroupID.begin(); it!=mGroupID.end(); it++) + { + LLUUID group_id = *it; + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); + if (group_data && group_data->mInsigniaID.notNull()) + { + mTabContainer->setTabImage(get_ptr_in_map(mSessions, group_id), group_data->mInsigniaID); + } + } + } +} + +void LLIMFloaterContainer::onCloseFloater(LLUUID id) +{ + LLAvatarPropertiesProcessor::instance().removeObserver(id, this); } LLIMFloaterContainer* LLIMFloaterContainer::findInstance() diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index d4a542dfc2..1333b098bc 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -33,12 +33,17 @@ #ifndef LL_LLIMFLOATERCONTAINER_H #define LL_LLIMFLOATERCONTAINER_H +#include +#include + #include "llfloater.h" #include "llmultifloater.h" +#include "llavatarpropertiesprocessor.h" +#include "llgroupmgr.h" class LLTabContainer; -class LLIMFloaterContainer : public LLMultiFloater +class LLIMFloaterContainer : public LLMultiFloater, public LLAvatarPropertiesObserver, public LLGroupMgrObserver { public: LLIMFloaterContainer(const LLSD& seed); @@ -51,15 +56,23 @@ public: BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); + void processProperties(void* data, EAvatarProcessorType type); + void changed(LLGroupChange gc); + static LLFloater* getCurrentVoiceFloater(); static LLIMFloaterContainer* findInstance(); static LLIMFloaterContainer* getInstance(); -protected: - - LLFloater* mActiveVoiceFloater; +private: + typedef std::map avatarID_panel_map_t; + avatarID_panel_map_t mSessions; + + typedef std::vector groupIDs_t; + groupIDs_t mGroupID; + + void onCloseFloater(LLUUID avatar_id); }; #endif // LL_LLIMFLOATERCONTAINER_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 950a4001c7..265c10aebd 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -55,6 +55,7 @@ #include "llfloaterchatterbox.h" #include "llimfloater.h" #include "llgroupiconctrl.h" +#include "llmd5.h" #include "llmutelist.h" #include "llrecentpeople.h" #include "llviewermessage.h" @@ -215,12 +216,14 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); } + buildHistoryFileName(); + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { std::list chat_history; //involves parsing of a chat history - LLLogChat::loadAllHistory(mName, chat_history); + LLLogChat::loadAllHistory(mHistoryFileName, chat_history); addMessagesFromHistory(chat_history); } } @@ -467,6 +470,44 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline() return !mOtherParticipantIsAvatar; } +void LLIMModel::LLIMSession::buildHistoryFileName() +{ + mHistoryFileName = mName; + + //ad-hoc requires sophisticated chat history saving schemes + if (isAdHoc()) + { + //in case of outgoing ad-hoc sessions + if (mInitialTargetIDs.size()) + { + std::set sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + mHistoryFileName = mName + " hash" + generateHash(sorted_uuids); + return; + } + + //in case of incoming ad-hoc sessions + mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4); + } +} + +//static +std::string LLIMModel::LLIMSession::generateHash(const std::set& sorted_uuids) +{ + LLMD5 md5_uuid; + + std::set::const_iterator it = sorted_uuids.begin(); + while (it != sorted_uuids.end()) + { + md5_uuid.update((unsigned char*)(*it).mData, 16); + it++; + } + md5_uuid.finalize(); + + LLUUID participants_md5_hash; + md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); + return participants_md5_hash.asString(); +} + void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) { @@ -614,11 +655,11 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, return true; } -bool LLIMModel::logToFile(const std::string& session_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) +bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) { - LLLogChat::saveHistory(session_name, from, from_id, utf8_text); + LLLogChat::saveHistory(file_name, from, from_id, utf8_text); return true; } else @@ -629,15 +670,7 @@ bool LLIMModel::logToFile(const std::string& session_name, const std::string& fr bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { - if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) - { - LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text); - return true; - } - else - { - return false; - } + return logToFile(LLIMModel::getInstance()->getHistoryFileName(session_id), from, from_id, utf8_text); } bool LLIMModel::proccessOnlineOfflineNotification( @@ -782,6 +815,18 @@ LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const return session->mSpeakers; } +const std::string& LLIMModel::getHistoryFileName(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << " does not exist " << llendl; + return LLStringUtil::null; + } + + return session->mHistoryFileName; +} + // TODO get rid of other participant ID void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index a226d66b12..a3b4f78af0 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -69,6 +69,8 @@ public: void addMessagesFromHistory(const std::list& history); 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, const LLVoiceChannel::EDirection& direction); + + /** @deprecated */ static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); bool isAdHoc(); @@ -80,12 +82,20 @@ public: bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} bool isAvalineSessionType() const { return mSessionType == AVALINE_SESSION;} + //*TODO make private + /** ad-hoc sessions involve sophisticated chat history file naming schemes */ + void buildHistoryFileName(); + + //*TODO make private + static std::string generateHash(const std::set& sorted_uuids); + LLUUID mSessionID; std::string mName; EInstantMessage mType; SType mSessionType; LLUUID mOtherParticipantID; std::vector mInitialTargetIDs; + std::string mHistoryFileName; // connection to voice channel state change signal boost::signals2::connection mVoiceChannelStateChangeConnection; @@ -231,6 +241,8 @@ public: */ LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; + const std::string& getHistoryFileName(const LLUUID& session_id) const; + static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id); static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, const std::vector& ids, EInstantMessage dialog); @@ -243,7 +255,7 @@ public: /** * Saves an IM message into a file */ - bool logToFile(const std::string& session_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); + bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); private: diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 7ef73d8ebf..8aaa95364c 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -688,7 +688,7 @@ void LLInspectAvatar::onToggleMute() void LLInspectAvatar::onClickReport() { - LLFloaterReporter::showFromObject(mAvatarID); + LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName); closeFloater(); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 099f863dc9..2f4f285065 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3687,18 +3687,6 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, return rv; } -BOOL LLCallingCardBridge::removeItem() -{ - if (LLFriendCardsManager::instance().isItemInAnyFriendsList(getItem())) - { - LLAvatarActions::removeFriendDialog(getItem()->getCreatorUUID()); - return FALSE; - } - else - { - return LLItemBridge::removeItem(); - } -} // +=================================================+ // | LLNotecardBridge | // +=================================================+ diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index fced0047e8..759d0cba18 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -448,7 +448,6 @@ public: EDragAndDropType cargo_type, void* cargo_data); void refreshFolderViewItem(); - BOOL removeItem(); protected: LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 75b7f9313b..8956a5e1bb 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -43,8 +43,11 @@ #include "lltrans.h" #include "lluictrlfactory.h" #include "lltooltip.h" +#include "llnotificationsutil.h" +#include "llregionflags.h" // newview includes +#include "llagent.h" #include "llinventoryobserver.h" #include "lllandmarkactions.h" #include "lllandmarklist.h" @@ -56,6 +59,7 @@ #include "lltrans.h" #include "llviewerinventory.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "llviewercontrol.h" #include "llviewermenu.h" #include "llurllineeditorctrl.h" @@ -256,36 +260,42 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) voice_icon.tool_tip = LLTrans::getString("LocationCtrlVoiceTooltip"); voice_icon.mouse_opaque = true; mParcelIcon[VOICE_ICON] = LLUICtrlFactory::create(voice_icon); + mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, VOICE_ICON)); addChild(mParcelIcon[VOICE_ICON]); LLIconCtrl::Params fly_icon = p.fly_icon; fly_icon.tool_tip = LLTrans::getString("LocationCtrlFlyTooltip"); fly_icon.mouse_opaque = true; mParcelIcon[FLY_ICON] = LLUICtrlFactory::create(fly_icon); + mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, FLY_ICON)); addChild(mParcelIcon[FLY_ICON]); LLIconCtrl::Params push_icon = p.push_icon; push_icon.tool_tip = LLTrans::getString("LocationCtrlPushTooltip"); push_icon.mouse_opaque = true; mParcelIcon[PUSH_ICON] = LLUICtrlFactory::create(push_icon); + mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PUSH_ICON)); addChild(mParcelIcon[PUSH_ICON]); LLIconCtrl::Params build_icon = p.build_icon; build_icon.tool_tip = LLTrans::getString("LocationCtrlBuildTooltip"); build_icon.mouse_opaque = true; mParcelIcon[BUILD_ICON] = LLUICtrlFactory::create(build_icon); + mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, BUILD_ICON)); addChild(mParcelIcon[BUILD_ICON]); LLIconCtrl::Params scripts_icon = p.scripts_icon; scripts_icon.tool_tip = LLTrans::getString("LocationCtrlScriptsTooltip"); scripts_icon.mouse_opaque = true; mParcelIcon[SCRIPTS_ICON] = LLUICtrlFactory::create(scripts_icon); + mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SCRIPTS_ICON)); addChild(mParcelIcon[SCRIPTS_ICON]); LLIconCtrl::Params damage_icon = p.damage_icon; damage_icon.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip"); damage_icon.mouse_opaque = true; mParcelIcon[DAMAGE_ICON] = LLUICtrlFactory::create(damage_icon); + mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, DAMAGE_ICON)); addChild(mParcelIcon[DAMAGE_ICON]); LLTextBox::Params damage_text = p.damage_text; @@ -917,3 +927,45 @@ bool LLLocationInputCtrl::onLocationContextMenuItemEnabled(const LLSD& userdata) return false; } + +void LLLocationInputCtrl::onParcelIconClick(EParcelIcon icon) +{ + switch (icon) + { + case VOICE_ICON: + LLNotificationsUtil::add("NoVoice"); + break; + case FLY_ICON: + LLNotificationsUtil::add("NoFly"); + break; + case PUSH_ICON: + LLNotificationsUtil::add("PushRestricted"); + break; + case BUILD_ICON: + LLNotificationsUtil::add("NoBuild"); + break; + case SCRIPTS_ICON: + { + LLViewerRegion* region = gAgent.getRegion(); + if(region && region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS) + { + LLNotificationsUtil::add("ScriptsStopped"); + } + else if(region && region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) + { + LLNotificationsUtil::add("ScriptsNotRunning"); + } + else + { + LLNotificationsUtil::add("NoOutsideScripts"); + } + break; + } + case DAMAGE_ICON: + LLNotificationsUtil::add("NotSafe"); + break; + case ICON_COUNT: + break; + // no default to get compiler warning when a new icon gets added + } +} diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index 7959fab2de..607ccd4da6 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -102,6 +102,18 @@ public: void handleLoginComplete(); private: + + enum EParcelIcon + { + VOICE_ICON = 0, + FLY_ICON, + PUSH_ICON, + BUILD_ICON, + SCRIPTS_ICON, + DAMAGE_ICON, + ICON_COUNT + }; + friend class LLUICtrlFactory; LLLocationInputCtrl(const Params&); virtual ~LLLocationInputCtrl(); @@ -138,6 +150,7 @@ private: // callbacks bool onLocationContextMenuItemEnabled(const LLSD& userdata); void onLocationContextMenuItemClicked(const LLSD& userdata); + void onParcelIconClick(EParcelIcon icon); LLMenuGL* mLocationContextMenu; LLButton* mAddLandmarkBtn; @@ -146,16 +159,6 @@ private: S32 mIconHPad; // pad between all icons S32 mAddLandmarkHPad; // pad to left of landmark star - enum EParcelIcon - { - VOICE_ICON = 0, - FLY_ICON, - PUSH_ICON, - BUILD_ICON, - SCRIPTS_ICON, - DAMAGE_ICON, - ICON_COUNT - }; LLIconCtrl* mParcelIcon[ICON_COUNT]; LLTextBox* mDamageText; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 4e5aaeb66a..dc187bf36c 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -237,15 +237,15 @@ void append_to_last_message(std::list& messages, const std::string& line) messages.back()[IM_TEXT] = im_text; } -void LLLogChat::loadAllHistory(const std::string& session_name, std::list& messages) +void LLLogChat::loadAllHistory(const std::string& file_name, std::list& messages) { - if (session_name.empty()) + if (file_name.empty()) { llwarns << "Session name is Empty!" << llendl; return ; } - LLFILE* fptr = LLFile::fopen(makeLogFileName(session_name), "r"); /*Flawfinder: ignore*/ + LLFILE* fptr = LLFile::fopen(makeLogFileName(file_name), "r"); /*Flawfinder: ignore*/ if (!fptr) return; //No previous conversation with this name. char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 3d3f5c4458..4290e4bbc0 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -56,7 +56,7 @@ public: void (*callback)(ELogLineType, const LLSD&, void*), void* userdata); - static void loadAllHistory(const std::string& session_name, std::list& messages); + static void loadAllHistory(const std::string& file_name, std::list& messages); private: static std::string cleanFileName(std::string filename); }; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 85e95ca1d6..176f7c7002 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -165,6 +165,8 @@ BOOL LLPanelAvatarNotes::postBuild() resetControls(); resetData(); + LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); + return TRUE; } @@ -337,6 +339,8 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes() if(getAvatarId().notNull()) { LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + if(LLVoiceClient::getInstance()) + LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); } } @@ -346,6 +350,17 @@ void LLPanelAvatarNotes::changed(U32 mask) childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId())); } +// virtual +void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +} + void LLPanelAvatarNotes::setAvatarId(const LLUUID& id) { if(id.notNull()) @@ -437,7 +452,6 @@ void LLPanelProfileTab::updateButtons() bool enable_map_btn = is_avatar_online && gAgent.isGodlike() || is_agent_mappable(getAvatarId()); childSetEnabled("show_on_map_btn", enable_map_btn); - childSetEnabled("call", LLAvatarActions::canCall(getAvatarId())); } ////////////////////////////////////////////////////////////////////////// @@ -485,6 +499,8 @@ BOOL LLPanelAvatarProfile::postBuild() pic = getChild("real_world_pic"); pic->setFallbackImageName("default_profile_picture.j2c"); + LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); + resetControls(); resetData(); @@ -757,6 +773,8 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile() if(getAvatarId().notNull()) { LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + if(LLVoiceClient::getInstance()) + LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); } } @@ -766,6 +784,17 @@ void LLPanelAvatarProfile::changed(U32 mask) childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId())); } +// virtual +void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +} + void LLPanelAvatarProfile::setAvatarId(const LLUUID& id) { if(id.notNull()) diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 22efa5dc35..1174c72d60 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -36,6 +36,7 @@ #include "llpanel.h" #include "llavatarpropertiesprocessor.h" #include "llcallingcard.h" +#include "llvoiceclient.h" class LLComboBox; class LLLineEditor; @@ -122,6 +123,7 @@ private: class LLPanelAvatarProfile : public LLPanelProfileTab , public LLFriendObserver + , public LLVoiceClientStatusObserver { public: LLPanelAvatarProfile(); @@ -134,6 +136,10 @@ public: */ virtual void changed(U32 mask); + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + /*virtual*/ void setAvatarId(const LLUUID& id); /** @@ -257,6 +263,7 @@ private: class LLPanelAvatarNotes : public LLPanelProfileTab , public LLFriendObserver + , public LLVoiceClientStatusObserver { public: LLPanelAvatarNotes(); @@ -269,6 +276,10 @@ public: */ virtual void changed(U32 mask); + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ BOOL postBuild(); diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 01b3f3bb7f..3f5d80c123 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -1689,7 +1689,7 @@ void LLPanelClassifiedEdit::onSaveClick() { if(gStatusBar->getBalance() < getPriceForListing()) { - LLNotificationsUtil::add("ClassifiedInsuffisientFunds"); + LLNotificationsUtil::add("ClassifiedInsufficientFunds"); return; } } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ee0426c7df..8c5208678e 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -65,6 +65,7 @@ #include "llvovolume.h" #include "lluictrlfactory.h" #include "llpluginclassmedia.h" +#include "llviewertexturelist.h" // // Methods @@ -406,14 +407,40 @@ void LLPanelFace::getState() LLUUID id; struct f1 : public LLSelectedTEGetFunctor { - LLUUID get(LLViewerObject* object, S32 te) + LLUUID get(LLViewerObject* object, S32 te_index) { - LLViewerTexture* image = object->getTEImage(te); - return image ? image->getID() : LLUUID::null; + LLUUID id; + + LLViewerTexture* image = object->getTEImage(te_index); + if (image) id = image->getID(); + + if (!id.isNull() && LLViewerMedia::textureHasMedia(id)) + { + LLTextureEntry *te = object->getTE(te_index); + if (te) + { + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL ; + if(!tex) + { + tex = LLViewerFetchedTexture::sDefaultImagep; + } + if (tex) + { + id = tex->getID(); + } + } + } + return id; } } func; identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id ); + if(LLViewerMedia::textureHasMedia(id)) + { + childSetEnabled("textbox autofix",editable); + childSetEnabled("button align",editable); + } + if (identical) { // All selected have the same texture @@ -444,13 +471,6 @@ void LLPanelFace::getState() } } } - - if(LLViewerMedia::textureHasMedia(id)) - { - childSetEnabled("textbox autofix",editable); - childSetEnabled("button align",editable); - } - } diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 01291c4012..c37fc59745 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -101,6 +101,8 @@ LLPanelGroup::LLPanelGroup() LLPanelGroup::~LLPanelGroup() { LLGroupMgr::getInstance()->removeObserver(this); + if(LLVoiceClient::getInstance()) + LLVoiceClient::getInstance()->removeObserver(this); } void LLPanelGroup::onOpen(const LLSD& key) @@ -188,6 +190,8 @@ BOOL LLPanelGroup::postBuild() if(panel_general) panel_general->setupCtrls(this); + + LLVoiceClient::getInstance()->addObserver(this); return TRUE; } @@ -300,6 +304,17 @@ void LLPanelGroup::changed(LLGroupChange gc) update(gc); } +// virtual +void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + childSetEnabled("btn_call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); +} + void LLPanelGroup::notifyObservers() { changed(GC_ALL); @@ -425,6 +440,11 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) getChild("group_name")->setVisible(false); getChild("group_name_editor")->setVisible(true); + + if(button_call) + button_call->setVisible(false); + if(button_chat) + button_chat->setVisible(false); } else { @@ -452,6 +472,10 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) if(button_apply) button_apply->setVisible(is_member); + if(button_call) + button_call->setVisible(is_member); + if(button_chat) + button_chat->setVisible(is_member); } reposButtons(); diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 7ea5e67b44..8c84695677 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -35,6 +35,7 @@ #include "llgroupmgr.h" #include "llpanel.h" #include "lltimer.h" +#include "llvoiceclient.h" struct LLOfferInfo; @@ -47,7 +48,8 @@ class LLAgent; class LLPanelGroup : public LLPanel, - public LLGroupMgrObserver + public LLGroupMgrObserver, + public LLVoiceClientStatusObserver { public: LLPanelGroup(); @@ -64,6 +66,10 @@ public: // Group manager observer trigger. virtual void changed(LLGroupChange gc); + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + void showNotice(const std::string& subject, const std::string& message, const bool& has_inventory, diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 0e55ff3214..45f0381d6f 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -452,6 +452,7 @@ LLPanelGroupSubTab::LLPanelGroupSubTab() : LLPanelGroupTab(), mHeader(NULL), mFooter(NULL), + mActivated(false), mSearchEditor(NULL) { } @@ -504,13 +505,14 @@ void LLPanelGroupSubTab::setGroupID(const LLUUID& id) mSearchEditor->clear(); setSearchFilter(""); } + + mActivated = false; } void LLPanelGroupSubTab::setSearchFilter(const std::string& filter) { if(mSearchFilter == filter) return; - lldebugs << "LLPanelGroupSubTab::setSearchFilter() ==> '" << filter << "'" << llendl; mSearchFilter = filter; LLStringUtil::toLower(mSearchFilter); update(GC_ALL); @@ -518,13 +520,11 @@ void LLPanelGroupSubTab::setSearchFilter(const std::string& filter) void LLPanelGroupSubTab::activate() { - lldebugs << "LLPanelGroupSubTab::activate()" << llendl; setOthersVisible(TRUE); } void LLPanelGroupSubTab::deactivate() { - lldebugs << "LLPanelGroupSubTab::deactivate()" << llendl; setOthersVisible(FALSE); } @@ -534,19 +534,11 @@ void LLPanelGroupSubTab::setOthersVisible(BOOL b) { mHeader->setVisible( b ); } - else - { - llwarns << "LLPanelGroupSubTab missing header!" << llendl; - } if (mFooter) { mFooter->setVisible( b ); } - else - { - llwarns << "LLPanelGroupSubTab missing footer!" << llendl; - } } bool LLPanelGroupSubTab::matchesActionSearchFilter(std::string action) @@ -875,10 +867,12 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() for (itor = selection.begin(); itor != selection.end(); ++itor) { - selected_members.push_back( (*itor)->getUUID() ); + LLUUID member_id = (*itor)->getValue()["uuid"]; + + selected_members.push_back( member_id ); // Get this member's power mask including any unsaved changes - U64 powers = getAgentPowersBasedOnRoleChanges((*itor)->getUUID()); + U64 powers = getAgentPowersBasedOnRoleChanges( member_id ); allowed_by_all &= powers; allowed_by_some |= powers; @@ -1022,6 +1016,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() //last owner. We should check for this special case // -jwolk check->setEnabled(cb_enable); + item->setEnabled(cb_enable); } } else @@ -1098,7 +1093,8 @@ void LLPanelGroupMembersSubTab::handleEjectMembers() for (itor = selection.begin() ; itor != selection.end(); ++itor) { - selected_members.push_back((*itor)->getUUID()); + LLUUID member_id = (*itor)->getValue()["uuid"]; + selected_members.push_back( member_id ); } mMembersList->deleteSelectedItems(); @@ -1154,7 +1150,8 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, for (std::vector::iterator itor = selection.begin() ; itor != selection.end(); ++itor) { - member_id = (*itor)->getUUID(); + + member_id = (*itor)->getValue()["uuid"]; //see if we requested a change for this member before if ( mMemberRoleChangeData.find(member_id) == mMemberRoleChangeData.end() ) @@ -1245,15 +1242,19 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick() LLScrollListItem* selected = mMembersList->getFirstSelected(); if (selected) { - LLAvatarActions::showProfile(selected->getUUID()); + LLUUID member_id = selected->getValue()["uuid"]; + LLAvatarActions::showProfile( member_id ); } } void LLPanelGroupMembersSubTab::activate() { LLPanelGroupSubTab::activate(); - - update(GC_ALL); + if(!mActivated) + { + update(GC_ALL); + mActivated = true; + } } void LLPanelGroupMembersSubTab::deactivate() @@ -1629,7 +1630,9 @@ void LLPanelGroupMembersSubTab::updateMembers() row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus(); row["columns"][2]["font"] = "SANSSERIF_SMALL"; - mMembersList->addElement(row);//, ADD_SORTED); + LLScrollListItem* member = mMembersList->addElement(row);//, ADD_SORTED); + + LLUUID id = member->getValue()["uuid"]; mHasMatch = TRUE; } } diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 2f81900e60..eac22a6338 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -149,6 +149,8 @@ protected: icon_map_t mActionIcons; + bool mActivated; + void setOthersVisible(BOOL b); }; diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index c0b2a40d46..7fd2c98cb1 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -64,36 +64,25 @@ void LLPanelChatControlPanel::onOpenVoiceControlsClicked() LLFloaterReg::showInstance("voice_controls"); } +void LLPanelChatControlPanel::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + updateCallButton(); +} + void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) { updateButtons(new_state >= LLVoiceChannel::STATE_CALL_STARTED); } -void LLPanelChatControlPanel::updateButtons(bool is_call_started) +void LLPanelChatControlPanel::updateCallButton() { - childSetVisible("end_call_btn_panel", is_call_started); - childSetVisible("voice_ctrls_btn_panel", is_call_started); - childSetVisible("call_btn_panel", ! is_call_started); -} - -LLPanelChatControlPanel::~LLPanelChatControlPanel() -{ - mVoiceChannelStateChangeConnection.disconnect(); -} - -BOOL LLPanelChatControlPanel::postBuild() -{ - childSetAction("call_btn", boost::bind(&LLPanelChatControlPanel::onCallButtonClicked, this)); - childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this)); - childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this)); - - return TRUE; -} - -void LLPanelChatControlPanel::draw() -{ - // hide/show start call and end call buttons - bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled(); + // hide/show call button + bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); if (!session) return; @@ -105,8 +94,33 @@ void LLPanelChatControlPanel::draw() && voice_enabled && callback_enabled; childSetEnabled("call_btn", enable_connect); +} - LLPanel::draw(); +void LLPanelChatControlPanel::updateButtons(bool is_call_started) +{ + childSetVisible("end_call_btn_panel", is_call_started); + childSetVisible("voice_ctrls_btn_panel", is_call_started); + childSetVisible("call_btn_panel", ! is_call_started); + updateCallButton(); + +} + +LLPanelChatControlPanel::~LLPanelChatControlPanel() +{ + mVoiceChannelStateChangeConnection.disconnect(); + if(LLVoiceClient::getInstance()) + LLVoiceClient::getInstance()->removeObserver(this); +} + +BOOL LLPanelChatControlPanel::postBuild() +{ + childSetAction("call_btn", boost::bind(&LLPanelChatControlPanel::onCallButtonClicked, this)); + childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this)); + childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this)); + + LLVoiceClient::getInstance()->addObserver(this); + + return TRUE; } void LLPanelChatControlPanel::setSessionId(const LLUUID& session_id) @@ -245,7 +259,6 @@ void LLPanelIMControlPanel::nameUpdatedCallback(const LLUUID& id, const std::str LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id): mParticipantList(NULL) { - mSpeakerManager = LLIMModel::getInstance()->getSpeakerManager(session_id); } BOOL LLPanelGroupControlPanel::postBuild() @@ -264,12 +277,11 @@ LLPanelGroupControlPanel::~LLPanelGroupControlPanel() // virtual void LLPanelGroupControlPanel::draw() { - //Remove event does not raised until speakerp->mActivityTimer.hasExpired() is false, see LLSpeakerManager::update() - //so we need update it to raise needed event - mSpeakerManager->update(true); // Need to resort the participant list if it's in sort by recent speaker order. if (mParticipantList) mParticipantList->updateRecentSpeakersOrder(); + //* TODO: find better way to properly enable call button for group and remove this call from draw() + updateCallButton(); LLPanelChatControlPanel::draw(); } @@ -307,7 +319,10 @@ void LLPanelGroupControlPanel::setSessionId(const LLUUID& session_id) // for group and Ad-hoc chat we need to include agent into list if(!mParticipantList) - mParticipantList = new LLParticipantList(mSpeakerManager, getChild("speakers_list"), true,false); + { + LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(session_id); + mParticipantList = new LLParticipantList(speaker_manager, getChild("speakers_list"), true,false); + } } diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index c18be5a6df..3ab505a084 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -37,11 +37,11 @@ #include "llvoicechannel.h" #include "llcallingcard.h" -class LLSpeakerMgr; -class LLAvatarList; class LLParticipantList; -class LLPanelChatControlPanel : public LLPanel +class LLPanelChatControlPanel + : public LLPanel + , public LLVoiceClientStatusObserver { public: LLPanelChatControlPanel() : @@ -49,15 +49,21 @@ public: ~LLPanelChatControlPanel(); virtual BOOL postBuild(); - virtual void draw(); void onCallButtonClicked(); void onEndCallButtonClicked(); void onOpenVoiceControlsClicked(); + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + virtual void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state); void updateButtons(bool is_call_started); + + // Enables/disables call button depending on voice availability + void updateCallButton(); virtual void setSessionId(const LLUUID& session_id); const LLUUID& getSessionId() { return mSessionId; } @@ -110,7 +116,6 @@ public: protected: LLUUID mGroupID; - LLSpeakerMgr* mSpeakerManager; LLParticipantList* mParticipantList; diff --git a/indra/newview/llpanellandaudio.cpp b/indra/newview/llpanellandaudio.cpp index 920fca66f2..6a4c909759 100644 --- a/indra/newview/llpanellandaudio.cpp +++ b/indra/newview/llpanellandaudio.cpp @@ -37,6 +37,7 @@ // viewer includes #include "llmimetypes.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "lluictrlfactory.h" // library includes @@ -83,8 +84,14 @@ BOOL LLPanelLandAudio::postBuild() mCheckSoundLocal = getChild("check sound local"); childSetCommitCallback("check sound local", onCommitAny, this); - mRadioVoiceChat = getChild("parcel_voice_channel"); - childSetCommitCallback("parcel_voice_channel", onCommitAny, this); + mCheckParcelEnableVoice = getChild("parcel_enable_voice_channel"); + childSetCommitCallback("parcel_enable_voice_channel", onCommitAny, this); + + // This one is always disabled so no need for a commit callback + mCheckEstateDisabledVoice = getChild("parcel_enable_voice_channel_is_estate_disabled"); + + mCheckParcelVoiceLocal = getChild("parcel_enable_voice_channel_local"); + childSetCommitCallback("parcel_enable_voice_channel_local", onCommitAny, this); mMusicURLEdit = getChild("music_url"); childSetCommitCallback("music_url", onCommitAny, this); @@ -118,19 +125,33 @@ void LLPanelLandAudio::refresh() mMusicUrlCheck->set( parcel->getObscureMusic() ); mMusicUrlCheck->setEnabled( can_change_media ); - if(parcel->getParcelFlagAllowVoice()) + bool allow_voice = parcel->getParcelFlagAllowVoice(); + + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + if (region && region->isVoiceEnabled()) { - if(parcel->getParcelFlagUseEstateVoiceChannel()) - mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatEstate); - else - mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatPrivate); + mCheckEstateDisabledVoice->setVisible(false); + + mCheckParcelEnableVoice->setVisible(true); + mCheckParcelEnableVoice->setEnabled( can_change_media ); + mCheckParcelEnableVoice->set(allow_voice); + + mCheckParcelVoiceLocal->setEnabled( can_change_media && allow_voice ); } else { - mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatDisable); + // Voice disabled at estate level, overrides parcel settings + // Replace the parcel voice checkbox with a disabled one + // labelled with an explanatory message + mCheckEstateDisabledVoice->setVisible(true); + + mCheckParcelEnableVoice->setVisible(false); + mCheckParcelEnableVoice->setEnabled(false); + mCheckParcelVoiceLocal->setEnabled(false); } - mRadioVoiceChat->setEnabled( can_change_media ); + mCheckParcelEnableVoice->set(allow_voice); + mCheckParcelVoiceLocal->set(!parcel->getParcelFlagUseEstateVoiceChannel()); mMusicURLEdit->setText(parcel->getMusicURL()); mMusicURLEdit->setEnabled( can_change_media ); @@ -149,30 +170,11 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata) // Extract data from UI BOOL sound_local = self->mCheckSoundLocal->get(); - int voice_setting = self->mRadioVoiceChat->getSelectedIndex(); std::string music_url = self->mMusicURLEdit->getText(); U8 obscure_music = self->mMusicUrlCheck->get(); - - BOOL voice_enabled; - BOOL voice_estate_chan; - - switch(voice_setting) - { - default: - case kRadioVoiceChatEstate: - voice_enabled = TRUE; - voice_estate_chan = TRUE; - break; - case kRadioVoiceChatPrivate: - voice_enabled = TRUE; - voice_estate_chan = FALSE; - break; - case kRadioVoiceChatDisable: - voice_enabled = FALSE; - voice_estate_chan = FALSE; - break; - } + BOOL voice_enabled = self->mCheckParcelEnableVoice->get(); + BOOL voice_estate_chan = !self->mCheckParcelVoiceLocal->get(); // Remove leading/trailing whitespace (common when copying/pasting) LLStringUtil::trim(music_url); diff --git a/indra/newview/llpanellandaudio.h b/indra/newview/llpanellandaudio.h index de5da95fa4..19766a40b6 100644 --- a/indra/newview/llpanellandaudio.h +++ b/indra/newview/llpanellandaudio.h @@ -52,7 +52,9 @@ private: private: LLCheckBoxCtrl* mCheckSoundLocal; - LLRadioGroup* mRadioVoiceChat; + LLCheckBoxCtrl* mCheckParcelEnableVoice; + LLCheckBoxCtrl* mCheckEstateDisabledVoice; + LLCheckBoxCtrl* mCheckParcelVoiceLocal; LLLineEditor* mMusicURLEdit; LLCheckBoxCtrl* mMusicUrlCheck; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index d6e407a0ed..47feef496a 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -305,6 +305,29 @@ void LLLandmarksPanel::updateShowFolderState() ); } +void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus)) + { + return; + } + + if (selectItemInAccordionTab(mLandmarksInventoryPanel, "tab_landmarks", obj_id, take_keyboard_focus)) + { + return; + } + + if (selectItemInAccordionTab(mMyInventoryPanel, "tab_inventory", obj_id, take_keyboard_focus)) + { + return; + } + + if (selectItemInAccordionTab(mLibraryInventoryPanel, "tab_library", obj_id, take_keyboard_focus)) + { + return; + } +} + ////////////////////////////////////////////////////////////////////////// // PROTECTED METHODS ////////////////////////////////////////////////////////////////////////// @@ -350,6 +373,36 @@ LLFolderViewItem* LLLandmarksPanel::getCurSelectedItem() const return mCurrentSelectedList ? mCurrentSelectedList->getRootFolder()->getCurSelectedItem() : NULL; } +LLFolderViewItem* LLLandmarksPanel::selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list, + const std::string& tab_name, + const LLUUID& obj_id, + BOOL take_keyboard_focus) const +{ + if (!inventory_list) + return NULL; + + LLFolderView* folder_view = inventory_list->getRootFolder(); + + LLFolderViewItem* item = folder_view->getItemByID(obj_id); + if (!item) + return NULL; + + LLAccordionCtrlTab* tab = getChild(tab_name); + if (!tab->isExpanded()) + { + tab->changeOpenClose(false); + } + + folder_view->setSelection(item, FALSE, take_keyboard_focus); + + LLAccordionCtrl* accordion = getChild("landmarks_accordion"); + LLRect screen_rc; + localRectToScreen(item->getRect(), &screen_rc); + accordion->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); + + return item; +} + void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) { if(!panel) return; diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 569739237d..96b790844c 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -73,6 +73,11 @@ public: */ void updateShowFolderState(); + /** + * Selects item with "obj_id" in one of accordion tabs. + */ + void setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus); + protected: /** * @return true - if current selected panel is not null and selected item is a landmark @@ -81,6 +86,17 @@ protected: bool isReceivedFolderSelected() const; void doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb); LLFolderViewItem* getCurSelectedItem() const; + + /** + * Selects item with "obj_id" in "inventory_list" and scrolls accordion + * scrollbar to show the item. + * Returns pointer to the item if it is found in "inventory_list", otherwise NULL. + */ + LLFolderViewItem* selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list, + const std::string& tab_name, + const LLUUID& obj_id, + BOOL take_keyboard_focus) const; + void updateSortOrder(LLInventoryPanel* panel, bool byDate); //LLRemoteParcelInfoObserver interface diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index c14b282488..42a5c0b775 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -462,6 +462,9 @@ LLPanelPeople::~LLPanelPeople() delete mFriendListUpdater; delete mRecentListUpdater; + if(LLVoiceClient::getInstance()) + LLVoiceClient::getInstance()->removeObserver(this); + LLView::deleteViewByHandle(mGroupPlusMenuHandle); LLView::deleteViewByHandle(mNearbyViewSortMenuHandle); LLView::deleteViewByHandle(mFriendsViewSortMenuHandle); @@ -612,6 +615,8 @@ BOOL LLPanelPeople::postBuild() if(recent_view_sort) mRecentViewSortMenuHandle = recent_view_sort->getHandle(); + LLVoiceClient::getInstance()->addObserver(this); + // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); @@ -621,6 +626,17 @@ BOOL LLPanelPeople::postBuild() return TRUE; } +// virtual +void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + updateButtons(); +} + void LLPanelPeople::updateFriendList() { if (!mOnlineFriendList || !mAllFriendList) @@ -775,41 +791,20 @@ void LLPanelPeople::updateButtons() } } + bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled(); + buttonSetEnabled("teleport_btn", friends_tab_active && item_selected && isFriendOnline(selected_uuids.front())); buttonSetEnabled("view_profile_btn", item_selected); buttonSetEnabled("im_btn", multiple_selected); // allow starting the friends conference for multiple selection - buttonSetEnabled("call_btn", multiple_selected && canCall()); + buttonSetEnabled("call_btn", multiple_selected && enable_calls); buttonSetEnabled("share_btn", item_selected); // not implemented yet bool none_group_selected = item_selected && selected_id.isNull(); buttonSetEnabled("group_info_btn", !none_group_selected); - buttonSetEnabled("group_call_btn", !none_group_selected); + buttonSetEnabled("group_call_btn", !none_group_selected && enable_calls); buttonSetEnabled("chat_btn", !none_group_selected); } -bool LLPanelPeople::canCall() -{ - std::vector selected_uuids; - getCurrentItemIDs(selected_uuids); - - bool result = false; - - std::vector::const_iterator - id = selected_uuids.begin(), - uuids_end = selected_uuids.end(); - - for (;id != uuids_end; ++id) - { - if (LLAvatarActions::canCall(*id)) - { - result = true; - break; - } - } - - return result; -} - std::string LLPanelPeople::getActiveTabName() const { return mTabContainer->getCurrentPanel()->getName(); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 7580fdbeef..6d3d436156 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -36,13 +36,16 @@ #include #include "llcallingcard.h" // for avatar tracker +#include "llvoiceclient.h" class LLFilterEditor; class LLTabContainer; class LLAvatarList; class LLGroupList; -class LLPanelPeople : public LLPanel +class LLPanelPeople + : public LLPanel + , public LLVoiceClientStatusObserver { LOG_CLASS(LLPanelPeople); public: @@ -52,6 +55,9 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ bool notifyChildren(const LLSD& info); + // Implements LLVoiceClientStatusObserver::onChange() to enable call buttons + // when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); // internals class Updater; @@ -73,7 +79,6 @@ private: bool isFriendOnline(const LLUUID& id); bool isItemsFreeOfFriends(const std::vector& uuids); - bool canCall(); void updateButtons(); std::string getActiveTabName() const; diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index c1c10e6022..d9651a6045 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -183,20 +183,7 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) } else if (item == std::string("can_call")) { - bool result = false; - std::vector::const_iterator - id = mUUIDs.begin(), - uuids_end = mUUIDs.end(); - - for (;id != uuids_end; ++id) - { - if (LLAvatarActions::canCall(*id)) - { - result = true; - break; - } - } - return result; + return LLAvatarActions::canCall(); } return false; } diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index b80eb9db38..0c10f11bfc 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -34,26 +34,20 @@ #include "llpanelplaceinfo.h" -#include "roles_constants.h" #include "llsdutil.h" -#include "llsecondlifeurls.h" #include "llsdutil_math.h" + #include "llregionhandle.h" -#include "message.h" #include "lliconctrl.h" #include "lltextbox.h" #include "llagent.h" -#include "llavatarpropertiesprocessor.h" #include "llexpandabletextbox.h" #include "llpanelpick.h" #include "lltexturectrl.h" -#include "llviewerinventory.h" -#include "llviewerparcelmgr.h" #include "llviewerregion.h" -#include "llviewertexteditor.h" LLPanelPlaceInfo::LLPanelPlaceInfo() : LLPanel(), @@ -265,25 +259,6 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) } } -// virtual -void LLPanelPlaceInfo::handleVisibilityChange(BOOL new_visibility) -{ - LLPanel::handleVisibilityChange(new_visibility); - - LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); - if (!parcel_mgr) - return; - - // Remove land selection when panel hides. - if (!new_visibility) - { - if (!parcel_mgr->selectionEmpty()) - { - parcel_mgr->deselectLand(); - } - } -} - void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel) { std::string region_name = mRegionName->getText(); diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 7dfc7b2444..3091f7ed24 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -94,7 +94,6 @@ public: /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void handleVisibilityChange (BOOL new_visibility); // Create a pick for the location specified // by global_pos. diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 402d50ba9c..d892e2885b 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -257,6 +257,25 @@ void LLPanelPlaceProfile::processParcelInfo(const LLParcelData& parcel_data) } } +// virtual +void LLPanelPlaceProfile::handleVisibilityChange(BOOL new_visibility) +{ + LLPanel::handleVisibilityChange(new_visibility); + + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + if (!parcel_mgr) + return; + + // Remove land selection when panel hides. + if (!new_visibility) + { + if (!parcel_mgr->selectionEmpty()) + { + parcel_mgr->deselectUnused(); + } + } +} + void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, LLViewerRegion* region, const LLVector3d& pos_global, diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h index 8c30ca92fb..8ca9526875 100644 --- a/indra/newview/llpanelplaceprofile.h +++ b/indra/newview/llpanelplaceprofile.h @@ -52,6 +52,8 @@ public: /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); + /*virtual*/ void handleVisibilityChange(BOOL new_visibility); + // Displays information about the currently selected parcel // without sending a request to the server. // If is_current_parcel true shows "You Are Here" banner. diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index a71c8d8958..a4f0e55a93 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -289,88 +289,91 @@ BOOL LLPanelPlaces::postBuild() void LLPanelPlaces::onOpen(const LLSD& key) { - if(!mPlaceProfile || !mLandmarkInfo || key.size() == 0) + if (!mPlaceProfile || !mLandmarkInfo) return; - mFilterEditor->clear(); - onFilterEdit("", false); - - mPlaceInfoType = key["type"].asString(); - mPosGlobal.setZero(); - mItem = NULL; - isLandmarkEditModeOn = false; - togglePlaceInfoPanel(TRUE); - - if (mPlaceInfoType == AGENT_INFO_TYPE) + if (key.size() != 0) { - mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT); - } - else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) - { - mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); + mFilterEditor->clear(); + onFilterEdit("", false); - if (key.has("x") && key.has("y") && key.has("z")) + mPlaceInfoType = key["type"].asString(); + mPosGlobal.setZero(); + mItem = NULL; + isLandmarkEditModeOn = false; + togglePlaceInfoPanel(TRUE); + + if (mPlaceInfoType == AGENT_INFO_TYPE) { - mPosGlobal = LLVector3d(key["x"].asReal(), - key["y"].asReal(), - key["z"].asReal()); + mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT); } - else + else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { - mPosGlobal = gAgent.getPositionGlobal(); + mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); + + if (key.has("x") && key.has("y") && key.has("z")) + { + mPosGlobal = LLVector3d(key["x"].asReal(), + key["y"].asReal(), + key["z"].asReal()); + } + else + { + mPosGlobal = gAgent.getPositionGlobal(); + } + + mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal); + + // Disable Save button because there is no item to save yet. + // The button will be enabled in onLandmarkLoaded callback. + mSaveBtn->setEnabled(FALSE); } - - mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal); - - // Disable Save button because there is no item to save yet. - // The button will be enabled in onLandmarkLoaded callback. - mSaveBtn->setEnabled(FALSE); - } - else if (mPlaceInfoType == LANDMARK_INFO_TYPE) - { - mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); - - LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); - if (!item) - return; - - setItem(item); - } - else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) - { - if (key.has("id")) + else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { - LLUUID parcel_id = key["id"].asUUID(); - mPlaceProfile->setParcelID(parcel_id); + mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); - // query the server to get the global 3D position of this - // parcel - we need this for teleport/mapping functions. - mRemoteParcelObserver->setParcelID(parcel_id); + LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); + if (!item) + return; + + setItem(item); } - else + else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) { - mPosGlobal = LLVector3d(key["x"].asReal(), - key["y"].asReal(), - key["z"].asReal()); + if (key.has("id")) + { + LLUUID parcel_id = key["id"].asUUID(); + mPlaceProfile->setParcelID(parcel_id); + + // query the server to get the global 3D position of this + // parcel - we need this for teleport/mapping functions. + mRemoteParcelObserver->setParcelID(parcel_id); + } + else + { + mPosGlobal = LLVector3d(key["x"].asReal(), + key["y"].asReal(), + key["z"].asReal()); + mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal); + } + + mPlaceProfile->setInfoType(LLPanelPlaceInfo::PLACE); + } + else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + { + S32 index = key["id"].asInteger(); + + const LLTeleportHistoryStorage::slurl_list_t& hist_items = + LLTeleportHistoryStorage::getInstance()->getItems(); + + mPosGlobal = hist_items[index].mGlobalPos; + + mPlaceProfile->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal); } - mPlaceProfile->setInfoType(LLPanelPlaceInfo::PLACE); + updateVerbs(); } - else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) - { - S32 index = key["id"].asInteger(); - - const LLTeleportHistoryStorage::slurl_list_t& hist_items = - LLTeleportHistoryStorage::getInstance()->getItems(); - - mPosGlobal = hist_items[index].mGlobalPos; - - mPlaceProfile->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); - mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal); - } - - updateVerbs(); LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); if (!parcel_mgr) @@ -388,9 +391,12 @@ void LLPanelPlaces::onOpen(const LLSD& key) { parcel_mgr->removeObserver(mParcelObserver); + // Clear the reference to selection to allow its removal in deselectUnused(). + mParcel.clear(); + if (!parcel_mgr->selectionEmpty()) { - parcel_mgr->deselectLand(); + parcel_mgr->deselectUnused(); } } } @@ -765,23 +771,23 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) mPickPanel->reshape(rect.getWidth(), rect.getHeight()); mPickPanel->setRect(rect); } - else if (item == "add_to_favbar") - { - if ( mItem.notNull() ) - { - const LLUUID& favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - if ( favorites_id.notNull() ) - { - copy_inventory_item(gAgent.getID(), - mItem->getPermissions().getOwner(), - mItem->getUUID(), - favorites_id, - std::string(), - LLPointer(NULL)); - llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl; - } - } - } + else if (item == "add_to_favbar") + { + if ( mItem.notNull() ) + { + const LLUUID& favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if ( favorites_id.notNull() ) + { + copy_inventory_item(gAgent.getID(), + mItem->getPermissions().getOwner(), + mItem->getUUID(), + favorites_id, + std::string(), + LLPointer(NULL)); + llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl; + } + } + } } void LLPanelPlaces::onBackButtonClicked() @@ -826,6 +832,14 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) mLandmarkInfo->setVisible(FALSE); } + else if (mPlaceInfoType == AGENT_INFO_TYPE) + { + LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver); + + // Clear reference to parcel selection when closing place profile panel. + // LLViewerParcelMgr removes the selection if it has 1 reference to it. + mParcel.clear(); + } } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE || mPlaceInfoType == LANDMARK_INFO_TYPE) @@ -842,6 +856,33 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) mPlaceProfile->setVisible(FALSE); } + else + { + LLLandmarksPanel* landmarks_panel = + dynamic_cast(mTabContainer->getPanelByName("Landmarks")); + if (landmarks_panel && mItem.notNull()) + { + // If a landmark info is being closed we open the landmarks tab + // and set this landmark selected. + mTabContainer->selectTabPanel(landmarks_panel); + + landmarks_panel->setItemSelected(mItem->getUUID(), TRUE); + } + } + } +} + +// virtual +void LLPanelPlaces::handleVisibilityChange(BOOL new_visibility) +{ + LLPanel::handleVisibilityChange(new_visibility); + + if (!new_visibility && mPlaceInfoType == AGENT_INFO_TYPE) + { + LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver); + + // Clear reference to parcel selection when closing places panel. + mParcel.clear(); } } diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index 27b5911ebb..0eba7f3afc 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -97,6 +97,8 @@ private: void togglePickPanel(BOOL visible); void togglePlaceInfoPanel(BOOL visible); + /*virtual*/ void handleVisibilityChange(BOOL new_visibility); + void updateVerbs(); LLPanelPlaceInfo* getCurrentInfoPanel(); diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index dcb7e9e878..e64d297326 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -125,6 +125,8 @@ LLParticipantList::~LLParticipantList() delete mParticipantListMenu; mParticipantListMenu = NULL; } + + mAvatarList->setContextMenu(NULL); } void LLParticipantList::setSpeakingIndicatorsVisible(BOOL visible) @@ -430,6 +432,10 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu() LLContextMenu* main_menu = LLUICtrlFactory::getInstance()->createFromFile( "menu_participant_list.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); + // Don't show sort options for P2P chat + bool is_sort_visible = (mParent.mAvatarList && mParent.mAvatarList->size() > 1); + main_menu->setItemVisible("SortByName", is_sort_visible); + main_menu->setItemVisible("SortByRecentSpeakers", is_sort_visible); main_menu->setItemVisible("Moderator Options", isGroupModerator()); main_menu->arrangeAndClear(); @@ -455,11 +461,6 @@ void LLParticipantList::LLParticipantListMenu::show(LLView* spawning_view, const LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteSelected", false); LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteOthers", false); } - - // Don't show sort options for P2P chat - bool is_sort_visible = (mParent.mAvatarList && mParent.mAvatarList->size() > 1); - LLMenuGL::sMenuContainer->childSetVisible("SortByName", is_sort_visible); - LLMenuGL::sMenuContainer->childSetVisible("SortByRecentSpeakers", is_sort_visible); } void LLParticipantList::LLParticipantListMenu::sortParticipantList(const LLSD& userdata) @@ -626,7 +627,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& } else if (item == "can_call") { - return LLVoiceClient::getInstance()->voiceEnabled(); + return LLVoiceClient::getInstance()->voiceEnabled()&&LLVoiceClient::getInstance()->isVoiceWorking(); } return true; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index a857e30d4f..028807a6bd 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -380,138 +380,53 @@ void LLPreviewTexture::updateDimensions() mUpdateDimensions = FALSE; - S32 image_height = llmax(1, mImage->getFullHeight()); - S32 image_width = llmax(1, mImage->getFullWidth()); - // Attempt to make the image 1:1 on screen. - // If that fails, cut width by half. - S32 client_width = image_width; - S32 client_height = image_height; - S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE; - S32 vert_pad = PREVIEW_HEADER_SIZE + 2 * CLIENT_RECT_VPAD + LLPANEL_BORDER_WIDTH; - S32 max_client_width = gViewerWindow->getWindowWidthScaled() - horiz_pad; - S32 max_client_height = gViewerWindow->getWindowHeightScaled() - vert_pad; - - if (mAspectRatio > 0.f) - { - client_height = llceil((F32)client_width / mAspectRatio); - } - - while ((client_width > max_client_width) || - (client_height > max_client_height )) - { - client_width /= 2; - client_height /= 2; - } - - S32 view_width = client_width + horiz_pad; - S32 view_height = client_height + vert_pad; - // set text on dimensions display (should be moved out of here and into a callback of some sort) childSetTextArg("dimensions", "[WIDTH]", llformat("%d", mImage->getFullWidth())); childSetTextArg("dimensions", "[HEIGHT]", llformat("%d", mImage->getFullHeight())); - + + LLRect dim_rect; + childGetRect("dimensions", dim_rect); + + S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE; + // add space for dimensions and aspect ratio - S32 info_height = 0; - LLRect aspect_rect; - childGetRect("combo_aspect_ratio", aspect_rect); - S32 aspect_height = aspect_rect.getHeight(); - info_height += aspect_height + CLIENT_RECT_VPAD; - view_height += info_height; - - S32 button_height = 0; - - // add space for buttons - view_height += (BTN_HEIGHT + CLIENT_RECT_VPAD) * 3; - button_height = (BTN_HEIGHT + PREVIEW_PAD) * 3; + S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD; - view_width = llmax(view_width, getMinWidth()); - view_height = llmax(view_height, getMinHeight()); - - if (view_height != mLastHeight || view_width != mLastWidth) - { - if (getHost()) - { - getHost()->growToFit(view_width, view_height); - reshape( view_width, view_height ); - setOrigin( 0, getHost()->getRect().getHeight() - (view_height + PREVIEW_HEADER_SIZE) ); - } - else - { - S32 old_top = getRect().mTop; - S32 old_left = getRect().mLeft; - reshape( view_width, view_height ); - S32 new_bottom = old_top - getRect().getHeight(); - setOrigin( old_left, new_bottom ); - } - - // Try to keep whole view onscreen, don't allow partial offscreen. - if (getHost()) - gFloaterView->adjustToFitScreen(getHost(), FALSE); - else - gFloaterView->adjustToFitScreen(this, FALSE); - - if (image_height > 1 && image_width > 1) - { - // Resize until we know the image's height - mLastWidth = view_width; - mLastHeight = view_height; - } - } - - if (!mUserResized) - { - // clamp texture size to fit within actual size of floater after attempting resize - client_width = llmin(client_width, getRect().getWidth() - horiz_pad); - client_height = llmin(client_height, getRect().getHeight() - PREVIEW_HEADER_SIZE - - (2 * CLIENT_RECT_VPAD) - LLPANEL_BORDER_WIDTH - info_height); + LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0); + client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD); + client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ; - - } - else - { - client_width = getRect().getWidth() - horiz_pad; - if (mAspectRatio > 0) - { - client_height = llround(client_width / mAspectRatio); - } - else - { - client_height = getRect().getHeight() - vert_pad; - } - } - - S32 max_height = getRect().getHeight() - PREVIEW_BORDER - button_height - - CLIENT_RECT_VPAD - info_height - CLIENT_RECT_VPAD - PREVIEW_HEADER_SIZE; + S32 client_width = client_rect.getWidth(); + S32 client_height = client_rect.getHeight(); if (mAspectRatio > 0.f) { - max_height = llmax(max_height, 1); - - if (client_height > max_height) + if(mAspectRatio > 1.f) { - client_height = max_height; - client_width = llround(client_height * mAspectRatio); + client_height = llceil((F32)client_width / mAspectRatio); + if(client_height > client_rect.getHeight()) + { + client_height = client_rect.getHeight(); + client_width = llceil((F32)client_height * mAspectRatio); + } + } + else + { + client_width = llceil((F32)client_height * mAspectRatio); + if(client_width > client_rect.getWidth()) + { + client_width = client_rect.getWidth(); + client_height = llceil((F32)client_width / mAspectRatio); + } } } - else - { - S32 max_width = getRect().getWidth() - horiz_pad; - client_height = llclamp(client_height, 1, max_height); - client_width = llclamp(client_width, 1, max_width); - } - - LLRect window_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - window_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD); - window_rect.mBottom += PREVIEW_BORDER + button_height + CLIENT_RECT_VPAD + info_height + CLIENT_RECT_VPAD; + mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height); - mClientRect.setLeftTopAndSize(window_rect.getCenterX() - (client_width / 2), window_rect.mTop, client_width, client_height); - // Hide the aspect ratio label if the window is too narrow // Assumes the label should be to the right of the dimensions - LLRect dim_rect, aspect_label_rect; + LLRect aspect_label_rect; childGetRect("aspect_ratio", aspect_label_rect); - childGetRect("dimensions", dim_rect); childSetVisible("aspect_ratio", dim_rect.mRight < aspect_label_rect.mLeft); } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 0dfc895bc3..a161588ddd 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -44,7 +44,6 @@ #include "llvoavatar.h" #include "llworld.h" -const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); @@ -73,8 +72,6 @@ LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerTy } LLVoiceClient::getInstance()->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id)); - - mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); } @@ -164,6 +161,89 @@ bool LLSortRecentSpeakers::operator()(const LLPointer lhs, const LLPo return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); } +LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id) +: LLEventTimer(action_period) +, mActionCallback(action_cb) +, mSpeakerId(speaker_id) +{ +} + +BOOL LLSpeakerActionTimer::tick() +{ + if (mActionCallback) + { + return (BOOL)mActionCallback(mSpeakerId); + } + return TRUE; +} + +LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay) +: mActionCallback(action_cb) +, mActionDelay(action_delay) +{ +} + +LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() +{ + removeAllTimers(); +} + +void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) +{ + bool not_found = true; + if (mActionTimersMap.size() > 0) + { + not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); + } + + // If there is already a started timer for the passed UUID don't do anything. + if (not_found) + { + // Starting a timer to remove an participant after delay is completed + mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, + new LLSpeakerActionTimer( + boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), + mActionDelay, speaker_id))); + } +} + +void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) +{ + if (mActionTimersMap.size() == 0) return; + + LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); + + if (it_speaker != mActionTimersMap.end()) + { + delete it_speaker->second; + mActionTimersMap.erase(it_speaker); + } +} + +void LLSpeakersDelayActionsStorage::removeAllTimers() +{ + LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); + for (; iter != mActionTimersMap.end(); ++iter) + { + delete iter->second; + } + mActionTimersMap.clear(); +} + +bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id) +{ + unsetActionTimer(speaker_id); + + if (mActionCallback) + { + mActionCallback(speaker_id); + } + + // do not return true to avoid deleting of an timer twice: + // in LLSpeakersDelayActionsStorage::unsetActionTimer() & LLEventTimer::updateClass() + return false; +} + // // LLSpeakerMgr @@ -172,10 +252,14 @@ bool LLSortRecentSpeakers::operator()(const LLPointer lhs, const LLPo LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : mVoiceChannel(channelp) { + static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); + + mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); } LLSpeakerMgr::~LLSpeakerMgr() { + delete mSpeakerDelayRemover; } LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) @@ -198,7 +282,6 @@ LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin { // keep highest priority status (lowest value) instead of overriding current value speakerp->mStatus = llmin(speakerp->mStatus, status); - speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id // we need to override speakers that we think are objects when we find out they are really // residents @@ -210,6 +293,8 @@ LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin } } + mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); + return speakerp; } @@ -314,7 +399,7 @@ void LLSpeakerMgr::update(BOOL resort_ok) S32 sort_index = 0; speaker_list_t::iterator sorted_speaker_it; for(sorted_speaker_it = mSpeakersSorted.begin(); - sorted_speaker_it != mSpeakersSorted.end(); ) + sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) { LLPointer speakerp = *sorted_speaker_it; @@ -327,19 +412,6 @@ void LLSpeakerMgr::update(BOOL resort_ok) // stuff sort ordinal into speaker so the ui can sort by this value speakerp->mSortIndex = sort_index++; - - // remove speakers that have been gone too long - if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired()) - { - fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove"); - - mSpeakers.erase(speakerp->mID); - sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it); - } - else - { - ++sorted_speaker_it; - } } } @@ -365,6 +437,35 @@ void LLSpeakerMgr::updateSpeakerList() } } +void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp) +{ + speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + speakerp->mDotColor = INACTIVE_COLOR; + mSpeakerDelayRemover->setActionTimer(speakerp->mID); +} + +bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) +{ + mSpeakers.erase(speaker_id); + + speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); + + for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) + { + if (speaker_id == (*sorted_speaker_it)->mID) + { + mSpeakersSorted.erase(sorted_speaker_it); + break; + } + } + + fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); + + update(TRUE); + + return false; +} + LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) { //In some conditions map causes crash if it is empty(Windows only), adding check (EK) @@ -513,9 +614,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) { if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull()) { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); + setSpeakerNotInChannel(speakerp); } else if (agent_data["transition"].asString() == "ENTER") { @@ -565,9 +664,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) std::string agent_transition = update_it->second.asString(); if (agent_transition == "LEAVE" && speakerp.notNull()) { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); + setSpeakerNotInChannel(speakerp); } else if ( agent_transition == "ENTER") { @@ -736,12 +833,13 @@ void LLActiveSpeakerMgr::updateSpeakerList() mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); // always populate from active voice channel - if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) + if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false { fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); mSpeakers.clear(); mSpeakersSorted.clear(); mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + mSpeakerDelayRemover->removeAllTimers(); } LLSpeakerMgr::updateSpeakerList(); @@ -802,9 +900,7 @@ void LLLocalSpeakerMgr::updateSpeakerList() LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS) { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); + setSpeakerNotInChannel(speakerp); } } } diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index da8dfdf548..63237204c8 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -73,7 +73,6 @@ public: F32 mLastSpokeTime; // timestamp when this speaker last spoke F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) std::string mDisplayName; // cache user name for this speaker - LLFrameTimer mActivityTimer; // time out speakers when they are not part of current voice channel BOOL mHasSpoken; // has this speaker said anything this session? BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? LLColor4 mDotColor; @@ -120,6 +119,92 @@ private: const LLUUID& mSpeakerID; }; +/** + * class LLSpeakerActionTimer + * + * Implements a timer that calls stored callback action for stored speaker after passed period. + * + * Action is called until callback returns "true". + * In this case the timer will be removed via LLEventTimer::updateClass(). + * Otherwise it should be deleted manually in place where it is used. + * If action callback is not set timer will tick only once and deleted. + */ +class LLSpeakerActionTimer : public LLEventTimer +{ +public: + typedef boost::function action_callback_t; + typedef std::map action_timers_map_t; + typedef action_timers_map_t::value_type action_value_t; + typedef action_timers_map_t::const_iterator action_timer_const_iter_t; + typedef action_timers_map_t::iterator action_timer_iter_t; + + /** + * Constructor. + * + * @param action_cb - callback which will be called each time after passed action period. + * @param action_period - time in seconds timer should tick. + * @param speaker_id - LLUUID of speaker which will be passed into action callback. + */ + LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); + virtual ~LLSpeakerActionTimer() {}; + + /** + * Implements timer "tick". + * + * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). + */ + virtual BOOL tick(); + +private: + action_callback_t mActionCallback; + LLUUID mSpeakerId; +}; + +/** + * Represents a functionality to store actions for speakers with delay. + * Is based on LLSpeakerActionTimer. + */ +class LLSpeakersDelayActionsStorage +{ +public: + LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); + ~LLSpeakersDelayActionsStorage(); + + /** + * Sets new LLSpeakerActionTimer with passed speaker UUID. + */ + void setActionTimer(const LLUUID& speaker_id); + + /** + * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and deletes it. + * + * @see onTimerActionCallback() + */ + void unsetActionTimer(const LLUUID& speaker_id); + + void removeAllTimers(); +private: + /** + * Callback of the each instance of LLSpeakerActionTimer. + * + * Unsets an appropriate timer instance and calls action callback for specified speacker_id. + * It always returns false to not use LLEventTimer::updateClass functionality of timer deleting. + * + * @see unsetActionTimer() + */ + bool onTimerActionCallback(const LLUUID& speaker_id); + + LLSpeakerActionTimer::action_timers_map_t mActionTimersMap; + LLSpeakerActionTimer::action_callback_t mActionCallback; + + /** + * Delay to call action callback for speakers after timer was set. + */ + F32 mActionDelay; + +}; + + class LLSpeakerMgr : public LLOldEvents::LLObservable { public: @@ -144,6 +229,8 @@ public: protected: virtual void updateSpeakerList(); + void setSpeakerNotInChannel(LLSpeaker* speackerp); + bool removeSpeaker(const LLUUID& speaker_id); typedef std::map > speaker_map_t; speaker_map_t mSpeakers; @@ -151,6 +238,11 @@ protected: speaker_list_t mSpeakersSorted; LLFrameTimer mSpeechTimer; LLVoiceChannel* mVoiceChannel; + + /** + * time out speakers when they are not part of current session + */ + LLSpeakersDelayActionsStorage* mSpeakerDelayRemover; }; class LLIMSpeakerMgr : public LLSpeakerMgr diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e8f5445c84..c2d3749a3a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -310,59 +310,6 @@ void update_texture_fetch() gTextureList.updateImages(0.10f); } -//Copies landmarks from the "Library" to "My Favorites" -void populate_favorites_bar() -{ - //*TODO consider extending LLInventoryModel::findCategoryUUIDForType(...) to support both root's - LLInventoryModel::cat_array_t* lib_cats = NULL; - LLInventoryModel::item_array_t* lib_items = NULL; - gInventory.getDirectDescendentsOf(gInventory.getLibraryRootFolderID(), lib_cats, lib_items); - if (!lib_cats) return; - - LLUUID lib_landmarks(LLUUID::null); - S32 count = lib_cats->count(); - for(S32 i = 0; i < count; ++i) - { - if(lib_cats->get(i)->getPreferredType() == LLFolderType::FT_LANDMARK) - { - lib_landmarks = lib_cats->get(i)->getUUID(); - break; - } - } - if (lib_landmarks.isNull()) - { - llerror("Library inventory is missing Landmarks", 0); - return; - } - - LLInventoryModel::cat_array_t* lm_cats = NULL; - LLInventoryModel::item_array_t* lm_items = NULL; - gInventory.getDirectDescendentsOf(lib_landmarks, lm_cats, lm_items); - if (!lm_items) return; - - const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - if (favorites_id.isNull()) - { - llerror("My Inventory is missing My Favorites", 0); - return; - } - - S32 lm_count = lm_items->count(); - for (S32 i = 0; i < lm_count; ++i) - { - LLInventoryItem* item = lm_items->get(i); - if (item->getUUID().isNull()) continue; - - copy_inventory_item(gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - favorites_id, - std::string(), - LLPointer(NULL)); - } -} - - // Returns false to skip other idle processing. Should only return // true when all initialization done. bool idle_startup() @@ -1703,12 +1650,6 @@ bool idle_startup() llinfos << "Creating Inventory Views" << llendl; LLFloaterReg::getInstance("inventory"); - //default initial content for Favorites Bar - if (gAgent.isFirstLogin()) - { - populate_favorites_bar(); - } - LLStartUp::setStartupState( STATE_MISC ); return FALSE; } diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 4a7d784c3e..84c8b9d5f0 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -1140,6 +1140,10 @@ LLTexLayerInterface::LLTexLayerInterface(const LLTexLayerInterface &layer, LLWea BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearable ) // This sets mInfo and calls initialization functions { //llassert(mInfo == NULL); // nyx says this is probably bogus but needs investigating + if (mInfo != NULL) // above llassert(), but softened into a warning + { + llwarns << "BAD STUFF! mInfo != NULL" << llendl; + } mInfo = info; //mID = info->mID; // No ID diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 9c4825763b..2b846d33fc 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1103,7 +1103,10 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) { if (op == TEXTURE_CANCEL) mViewModel->resetDirty(); - else + // If the "no_commit_on_selection" parameter is set + // we get dirty only when user presses OK in the picker + // (i.e. op == TEXTURE_SELECT) or texture changes via DnD. + else if (mCommitOnSelection || op == TEXTURE_SELECT) mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? if( floaterp->isDirty() ) @@ -1125,7 +1128,7 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) { // If the "no_commit_on_selection" parameter is set // we commit only when user presses OK in the picker - // (i.e. op == TEXTURE_SELECT) or changes texture via DnD. + // (i.e. op == TEXTURE_SELECT) or texture changes via DnD. if (mCommitOnSelection || op == TEXTURE_SELECT) onCommit(); } @@ -1165,6 +1168,9 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, { if(doDrop(item)) { + if (!mCommitOnSelection) + mViewModel->setDirty(); + // This removes the 'Multiple' overlay, since // there is now only one texture selected. setTentative( FALSE ); diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 023329a9b2..8ca92c3d87 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -74,7 +74,8 @@ public: Optional default_image_name; Optional allow_no_texture; Optional can_apply_immediately; - Optional no_commit_on_selection; // don't commit unless it's DnD or OK button press + Optional no_commit_on_selection; // alternative mode: commit occurs and the widget gets dirty + // only on DnD or when OK is pressed in the picker Optional label_width; Optional border_color; diff --git a/indra/newview/lltransientdockablefloater.cpp b/indra/newview/lltransientdockablefloater.cpp index 7e4d4988d1..c9bfe178ce 100644 --- a/indra/newview/lltransientdockablefloater.cpp +++ b/indra/newview/lltransientdockablefloater.cpp @@ -42,6 +42,7 @@ LLTransientDockableFloater::LLTransientDockableFloater(LLDockControl* dockContro LLDockableFloater(dockControl, uniqueDocking, key, params) { LLTransientFloaterMgr::getInstance()->registerTransientFloater(this); + LLTransientFloater::init(this); } LLTransientDockableFloater::~LLTransientDockableFloater() diff --git a/indra/newview/lltransientdockablefloater.h b/indra/newview/lltransientdockablefloater.h index 6e8a3afd22..e0541d6597 100644 --- a/indra/newview/lltransientdockablefloater.h +++ b/indra/newview/lltransientdockablefloater.h @@ -37,12 +37,13 @@ #include "llfloater.h" #include "lldockcontrol.h" #include "lldockablefloater.h" +#include "lltransientfloatermgr.h" /** * Represents floater that can dock and managed by transient floater manager. * Transient floaters should be hidden if user click anywhere except defined view list. */ -class LLTransientDockableFloater : public LLDockableFloater +class LLTransientDockableFloater : public LLDockableFloater, LLTransientFloater { public: LOG_CLASS(LLTransientDockableFloater); @@ -52,6 +53,7 @@ public: /*virtual*/ void setVisible(BOOL visible); /* virtual */void setDocked(bool docked, bool pop_on_undock = true); + virtual LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::GLOBAL; } }; #endif /* LL_TRANSIENTDOCKABLEFLOATER_H */ diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp index 347399f239..8f1a738453 100644 --- a/indra/newview/lltransientfloatermgr.cpp +++ b/indra/newview/lltransientfloatermgr.cpp @@ -44,57 +44,68 @@ LLTransientFloaterMgr::LLTransientFloaterMgr() { gViewerWindow->getRootView()->addMouseDownCallback(boost::bind( &LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3)); + + mGroupControls.insert(std::pair >(GLOBAL, std::set())); + mGroupControls.insert(std::pair >(IM, std::set())); } -void LLTransientFloaterMgr::registerTransientFloater(LLFloater* floater) +void LLTransientFloaterMgr::registerTransientFloater(LLTransientFloater* floater) { mTransSet.insert(floater); } -void LLTransientFloaterMgr::unregisterTransientFloater(LLFloater* floater) +void LLTransientFloaterMgr::unregisterTransientFloater(LLTransientFloater* floater) { mTransSet.erase(floater); } +void LLTransientFloaterMgr::addControlView(ETransientGroup group, LLView* view) +{ + mGroupControls.find(group)->second.insert(view); +} + +void LLTransientFloaterMgr::removeControlView(ETransientGroup group, LLView* view) +{ + mGroupControls.find(group)->second.erase(view); +} + void LLTransientFloaterMgr::addControlView(LLView* view) { - mControlsSet.insert(view); + addControlView(GLOBAL, view); } void LLTransientFloaterMgr::removeControlView(LLView* view) { // we will still get focus lost callbacks on this view, but that's ok // since we run sanity checking logic every time - mControlsSet.erase(view); + removeControlView(GLOBAL, view); } -void LLTransientFloaterMgr::hideTransientFloaters() +void LLTransientFloaterMgr::hideTransientFloaters(S32 x, S32 y) { - for (std::set::iterator it = mTransSet.begin(); it + for (std::set::iterator it = mTransSet.begin(); it != mTransSet.end(); it++) { - LLFloater* floater = *it; - if (floater->isDocked()) + LLTransientFloater* floater = *it; + if (floater->isTransientDocked()) { - floater->setVisible(FALSE); + ETransientGroup group = floater->getGroup(); + + bool hide = isControlClicked(mGroupControls.find(group)->second, x, y); + if (hide) + { + floater->setTransientVisible(FALSE); + } } } } -void LLTransientFloaterMgr::leftMouseClickCallback(S32 x, S32 y, - MASK mask) +bool LLTransientFloaterMgr::isControlClicked(std::set& set, S32 x, S32 y) { - bool hide = true; - for (controls_set_t::iterator it = mControlsSet.begin(); it - != mControlsSet.end(); it++) + bool res = true; + for (controls_set_t::iterator it = set.begin(); it + != set.end(); it++) { - // don't hide transient floater if any context menu opened - if (LLMenuGL::sMenuContainer->getVisibleMenu() != NULL) - { - hide = false; - break; - } - LLView* control_view = *it; if (!control_view->getVisible()) { @@ -105,14 +116,32 @@ void LLTransientFloaterMgr::leftMouseClickCallback(S32 x, S32 y, // if click inside view rect if (rect.pointInRect(x, y)) { - hide = false; + res = false; break; } } + return res; +} +void LLTransientFloaterMgr::leftMouseClickCallback(S32 x, S32 y, + MASK mask) +{ + // don't hide transient floater if any context menu opened + if (LLMenuGL::sMenuContainer->getVisibleMenu() != NULL) + { + return; + } + + bool hide = isControlClicked(mGroupControls.find(GLOBAL)->second, x, y); if (hide) { - hideTransientFloaters(); + hideTransientFloaters(x, y); } } +void LLTransientFloater::init(LLFloater* thiz) +{ + // used since LLTransientFloater(this) can't be used in descendant constructor parameter initialization. + mFloater = thiz; +} + diff --git a/indra/newview/lltransientfloatermgr.h b/indra/newview/lltransientfloatermgr.h index cef6e1fe45..1f99325a7f 100644 --- a/indra/newview/lltransientfloatermgr.h +++ b/indra/newview/lltransientfloatermgr.h @@ -37,27 +37,60 @@ #include "llsingleton.h" #include "llfloater.h" +class LLTransientFloater; /** * Provides functionality to hide transient floaters. */ class LLTransientFloaterMgr: public LLSingleton { -public: +protected: LLTransientFloaterMgr(); - void registerTransientFloater(LLFloater* floater); - void unregisterTransientFloater(LLFloater* floater); + friend class LLSingleton; + +public: + enum ETransientGroup + { + GLOBAL, IM + }; + + void registerTransientFloater(LLTransientFloater* floater); + void unregisterTransientFloater(LLTransientFloater* floater); + void addControlView(ETransientGroup group, LLView* view); + void removeControlView(ETransientGroup group, LLView* view); void addControlView(LLView* view); void removeControlView(LLView* view); private: - void hideTransientFloaters(); + void hideTransientFloaters(S32 x, S32 y); void leftMouseClickCallback(S32 x, S32 y, MASK mask); + bool isControlClicked(std::set& set, S32 x, S32 y); +private: + std::set mTransSet; + + typedef std::set controls_set_t; + typedef std::map > group_controls_t; + group_controls_t mGroupControls; +}; + +/** + * An abstract class declares transient floater interfaces. + */ +class LLTransientFloater +{ +protected: + /** + * Class initialization method. + * Should be called from descendant constructor. + */ + void init(LLFloater* thiz); +public: + virtual LLTransientFloaterMgr::ETransientGroup getGroup() = 0; + bool isTransientDocked() { return mFloater->isDocked(); }; + void setTransientVisible(BOOL visible) {mFloater->setVisible(visible); } private: - std::set mTransSet; - typedef std::set controls_set_t; - controls_set_t mControlsSet; + LLFloater* mFloater; }; #endif // LL_LLTRANSIENTFLOATERMGR_H diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 7b9b12108d..ba256d70e8 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -483,7 +483,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected"); render_ui(); - render_disconnected_background(); } ////////////////////////// @@ -1141,6 +1140,10 @@ void render_ui(F32 zoom_factor, int subfield) render_ui_3d(); LLGLState::checkStates(); } + else + { + render_disconnected_background(); + } render_ui_2d(); LLGLState::checkStates(); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 04d67fe750..d712446d83 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -752,6 +752,11 @@ void LLViewerMedia::updateMedia(void *dummy_arg) new_priority = LLPluginClassMedia::PRIORITY_NORMAL; impl_count_interest_normal++; } + else if(pimpl->isParcelMedia()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } else { // Look at interest and CPU usage for instances that aren't in any of the above states. diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 52f1de5ffa..fccd2b2e54 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1472,7 +1472,12 @@ void inventory_offer_handler(LLOfferInfo* info) { LLStringUtil::truncate(msg, indx); } - + + if(LLAssetType::AT_LANDMARK == info->mType) + { + msg = LLViewerInventoryItem::getDisplayName(msg); + } + LLSD args; args["[OBJECTNAME]"] = msg; @@ -2009,7 +2014,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Someone has offered us some inventory. { LLOfferInfo* info = new LLOfferInfo; - bool mute_im = false; if (IM_INVENTORY_OFFERED == dialog) { struct offer_agent_bucket_t @@ -2026,11 +2030,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; info->mType = (LLAssetType::EType) bucketp->asset_type; info->mObjectID = bucketp->object_id; - - if(accept_im_from_only_friend&&!is_friend) - { - mute_im = true; - } } else { @@ -2061,7 +2060,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mDesc = message; info->mHost = msg->getSender(); //if (((is_busy && !is_owned_by_me) || is_muted)) - if ( is_muted || mute_im) + if (is_muted) { // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) LLInventoryFetchObserver::item_ref_t items; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index e8b435fc8f..e87dbe5c07 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -212,22 +212,15 @@ void LLViewerParcelMedia::play(LLParcel* parcel) else { // Since the texture id is different, we need to generate a new impl - LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; // Delete the old one first so they don't fight over the texture. sMediaImpl = NULL; - - sMediaImpl = LLViewerMedia::newMediaImpl( - placeholder_texture_id, - media_width, - media_height, - media_auto_scale, - media_loop); - sMediaImpl->setIsParcelMedia(true); - sMediaImpl->navigateTo(media_url, mime_type, true); + + // A new impl will be created below. } } - else + + if(!sMediaImpl) { LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ad993bc056..3f42cba561 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1560,7 +1560,11 @@ F32 LLViewerFetchedTexture::calcDecodePriority() void LLViewerFetchedTexture::setDecodePriority(F32 priority) { - llassert(!mInImageList); + //llassert(!mInImageList); // firing a lot, figure out why + if (mInImageList) // above llassert() softened to a warning + { + llwarns << "BAD STUFF! mInImageList" << llendl; + } mDecodePriority = priority; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 6bb547373c..ee934ab9c5 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -502,7 +502,10 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) { llerrs << "LLViewerTextureList::addImageToList - Image already in list" << llendl; } - llverify((mImageList.insert(image)).second == true); + if ((mImageList.insert(image)).second != true) + { + llwarns << "BAD STUFF! (mImageList.insert(image)).second != true" << llendl; + } image->setInImageList(TRUE) ; } @@ -519,7 +522,10 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) } llerrs << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl; } - llverify(mImageList.erase(image) == 1); + if (mImageList.erase(image) != 1) + { + llwarns << "BAD STUFF! mImageList.erase(image) != 1" << llendl; + } image->setInImageList(FALSE) ; } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index ea83d999a6..7ccd484bfa 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -552,6 +552,15 @@ std::string LLVoiceClient::getDisplayName(const LLUUID& id) } } +bool LLVoiceClient::isVoiceWorking() +{ + if (mVoiceModule) + { + return mVoiceModule->isVoiceWorking(); + } + return false; +} + BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id) { if (mVoiceModule) diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 2cc99d9e45..dce24ff541 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -109,6 +109,8 @@ public: virtual void updateSettings()=0; // call after loading settings and whenever they change + virtual bool isVoiceWorking()=0; // connected to a voice server and voice channel + virtual const LLVoiceVersionInfo& getVersion()=0; ///////////////////// @@ -274,6 +276,8 @@ static const F32 OVERDRIVEN_POWER_LEVEL; void updateSettings(); // call after loading settings and whenever they change + bool isVoiceWorking(); // connected to a voice server and voice channel + // tuning void tuningStart(); void tuningStop(); @@ -397,7 +401,6 @@ static const F32 OVERDRIVEN_POWER_LEVEL; protected: LLVoiceModuleInterface* mVoiceModule; LLPumpIO *m_servicePump; - }; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 03b03b3884..5fa522a6b5 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -4584,6 +4584,11 @@ BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id) return result; } +bool LLVivoxVoiceClient::isVoiceWorking() +{ + return (stateLoggedIn <= mState) && (mState <= stateLeavingSession); +} + // Returns true if the indicated participant in the current audio session is really an SL avatar. // Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls. BOOL LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 17ee47c990..e3b6b1fa36 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -82,7 +82,9 @@ public: virtual const LLVoiceVersionInfo& getVersion(); virtual void updateSettings(); // call after loading settings and whenever they change - + + virtual bool isVoiceWorking(); // connected to a voice server and voice channel + ///////////////////// /// @name Tuning //@{ diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d5dd19e470..295c0c8010 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1852,12 +1852,22 @@ void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) if (mep && impl) { std::string url = mep->getCurrentURL(); + // Look for a ":", if not there, assume "http://" + if (!url.empty() && std::string::npos == url.find(':')) + { + url = "http://" + url; + } // If the url we're trying to "bounce back" to is either empty or not // allowed by the whitelist, try the home url. If *that* doesn't work, // set the media as failed and unload it if (url.empty() || !mep->checkCandidateUrl(url)) { url = mep->getHomeURL(); + // Look for a ":", if not there, assume "http://" + if (!url.empty() && std::string::npos == url.find(':')) + { + url = "http://" + url; + } } if (url.empty() || !mep->checkCandidateUrl(url)) { diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml index cdf1915d5e..faa24b5877 100644 --- a/indra/newview/skins/default/xui/da/floater_about.xml +++ b/indra/newview/skins/default/xui/da/floater_about.xml @@ -1,81 +1,81 @@ - - - - [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2] ([VIEWER_VERSION_3]) [BUILD_DATE] [BUILD_TIME] ([CHANNEL]) -[[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] - - - Bygget med [COMPILER] version [COMPILER_VERSION] - - - Du er ved [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1] i [REGION] lokaliseret på [HOSTNAME] ([HOSTIP]) -[SERVER_VERSION] -[[SERVER_RELEASE_NOTES_URL] [ReleaseNotes]] - - - CPU: [CPU] -Memory: [MEMORY_MB] MB -OS Version: [OS_VERSION] -Grafik kort mærke: [GRAPHICS_CARD_VENDOR] -Grafik kort: [GRAPHICS_CARD] - - - Windows Graphics Driver Version: [GRAPHICS_DRIVER_VERSION] - - - OpenGL Version: [OPENGL_VERSION] - -libcurl Version: [LIBCURL_VERSION] -J2C Decoder Version: [J2C_VERSION] -Audio Driver Version: [AUDIO_DRIVER_VERSION] -Qt Webkit Version: [QT_WEBKIT_VERSION] -Vivox Version: [VIVOX_VERSION] - - - (ingen) - - - Pakker tabt: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%) - - - -