From 6c70154cd1e5757e879f3f7463c0fedd69d82b63 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Wed, 30 Sep 2009 01:00:51 +0000 Subject: converted focus change callbacks to use signals replaced mFocusChangedSignal that PE added with our hierarchical focus mgmt reviewed by Leyla --- indra/llui/llcombobox.cpp | 1 - indra/llui/llfocusmgr.cpp | 42 ++++++----------------------------- indra/llui/llfocusmgr.h | 27 +++++++++------------- indra/llui/llmultisliderctrl.cpp | 2 +- indra/llui/llscrollbar.h | 6 ----- indra/llui/llsliderctrl.cpp | 2 +- indra/llui/llspinctrl.cpp | 2 +- indra/llui/lluictrl.cpp | 10 +-------- indra/llui/lluictrl.h | 7 ------ indra/llui/llview.cpp | 10 --------- indra/llui/llview.h | 4 ---- indra/newview/llchatbar.cpp | 8 +++---- indra/newview/llchatbar.h | 4 ++-- indra/newview/llfloaterland.cpp | 2 +- indra/newview/llfloaterpostcard.cpp | 2 +- indra/newview/llfolderview.cpp | 4 ++-- indra/newview/llfolderview.h | 2 +- indra/newview/llimfloater.cpp | 8 +++---- indra/newview/llimpanel.cpp | 9 +++----- indra/newview/llimpanel.h | 2 ++ indra/newview/lllocationinputctrl.cpp | 1 - indra/newview/llnearbychatbar.cpp | 2 +- indra/newview/llpanelclassified.cpp | 4 ++-- indra/newview/llpanelgroupgeneral.cpp | 4 ++-- indra/newview/llpanelgrouproles.cpp | 2 +- indra/newview/llpanellogin.cpp | 4 ++-- indra/newview/llpanellogin.h | 2 +- 27 files changed, 50 insertions(+), 123 deletions(-) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 58aeb61728..0170ac0c6a 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -483,7 +483,6 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p) params.max_length_bytes(mMaxChars); params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.focus_lost_callback(NULL); params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index ab9b59e252..279cbaa923 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -41,11 +41,6 @@ const F32 FOCUS_FADE_TIME = 0.3f; // NOTE: the LLFocusableElement implementation has been moved here from lluictrl.cpp. LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mTopLostCallback(NULL), - mFocusCallbackUserData(NULL) { } @@ -68,35 +63,19 @@ LLFocusableElement::~LLFocusableElement() void LLFocusableElement::onFocusReceived() { - if( mFocusReceivedCallback ) - { - mFocusReceivedCallback( this, mFocusCallbackUserData ); - } - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } + mFocusReceivedCallback(this); + mFocusChangedCallback(this); } void LLFocusableElement::onFocusLost() { - if( mFocusLostCallback ) - { - mFocusLostCallback( this, mFocusCallbackUserData ); - } - - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } + mFocusLostCallback(this); + mFocusChangedCallback(this); } void LLFocusableElement::onTopLost() { - if (mTopLostCallback) - { - mTopLostCallback(this, mFocusCallbackUserData); - } + mTopLostCallback(this); } BOOL LLFocusableElement::hasFocus() const @@ -188,12 +167,9 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL view_handle_list_t new_focus_list; // walk up the tree to root and add all views to the new_focus_list - for (LLView* ctrl = dynamic_cast(mKeyboardFocus); ctrl && ctrl != LLUI::getRootView(); ctrl = ctrl->getParent()) + for (LLView* ctrl = dynamic_cast(mKeyboardFocus); ctrl; ctrl = ctrl->getParent()) { - if (ctrl) - { - new_focus_list.push_back(ctrl->getHandle()); - } + new_focus_list.push_back(ctrl->getHandle()); } // remove all common ancestors since their focus is unchanged @@ -216,10 +192,6 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL { mCachedKeyboardFocusList.pop_front(); old_focus_view->onFocusLost(); - - // part of fix of EXT-996 - // this need to handle event when user click inside in-world area - mFocusChangeSignal(); } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 2c2dae216a..2fa4e124fb 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -54,11 +54,12 @@ public: virtual void setFocus( BOOL b ); virtual BOOL hasFocus() const; - typedef boost::function focus_callback_t; - void setFocusLostCallback(focus_callback_t cb, void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusReceivedCallback(focus_callback_t cb, void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusChangedCallback(focus_callback_t cb, void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } - void setTopLostCallback(focus_callback_t cb, void* user_data = NULL ) { mTopLostCallback = cb; mFocusCallbackUserData = user_data; } + typedef boost::signals2::signal focus_signal_t; + + boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb) { return mFocusLostCallback.connect(cb);} + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb) { return mFocusReceivedCallback.connect(cb);} + boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb) { return mFocusChangedCallback.connect(cb);} + void setTopLostCallback(const focus_signal_t::slot_type& cb) { mTopLostCallback.connect(cb);} // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); @@ -68,11 +69,10 @@ protected: virtual void onFocusReceived(); virtual void onFocusLost(); virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere - focus_callback_t mFocusLostCallback; - focus_callback_t mFocusReceivedCallback; - focus_callback_t mFocusChangedCallback; - focus_callback_t mTopLostCallback; - void* mFocusCallbackUserData; + focus_signal_t mFocusLostCallback; + focus_signal_t mFocusReceivedCallback; + focus_signal_t mFocusChangedCallback; + focus_signal_t mTopLostCallback; }; @@ -124,11 +124,6 @@ public: void unlockFocus(); BOOL focusLocked() const { return mLockedView != NULL; } - void addFocusChangeCallback(const boost::signals2::signal::slot_type& cb) - { - mFocusChangeSignal.connect(cb); - } - private: LLUICtrl* mLockedView; @@ -155,8 +150,6 @@ private: typedef std::map, LLHandle > focus_history_map_t; focus_history_map_t mFocusHistory; - boost::signals2::signal mFocusChangeSignal; - #ifdef _DEBUG std::string mMouseCaptorName; std::string mKeyboardFocusName; diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index 01a3b5fdc7..0fbb7ced54 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -140,7 +140,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.prevalidate_callback(&LLLineEditor::prevalidateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create (params); - mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::onEditorGainFocus ); + mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others //mEditor->setSelectAllonFocusReceived(TRUE); diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 7e72331a3f..7e88b16561 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -130,12 +130,6 @@ public: void onLineUpBtnPressed(const LLSD& data); void onLineDownBtnPressed(const LLSD& data); - void setBGColor(const LLUIColor& color) { mBGColor = color; } - const LLUIColor& getBGColor() const { return mBGColor; } - - void setBGVisible() { mBGVisible = true; } - bool getBGVisible() const { return mBGVisible; } - private: void updateThumbRect(); void changeLine(S32 delta, BOOL update_thumb ); diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 15584c8dc7..fb71b60725 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -143,7 +143,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) line_p.prevalidate_callback(&LLLineEditor::prevalidateFloat); mEditor = LLUICtrlFactory::create(line_p); - mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others //mEditor->setSelectAllonFocusReceived(TRUE); diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index 3a96bc8f93..83d71006aa 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -142,7 +142,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p) params.prevalidate_callback(&LLLineEditor::prevalidateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create (params); - mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus // than when it doesn't. Instead, if you always have to double click to select all the text, // it's easier to understand diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 8807e26f6b..2cd9c8844e 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -114,7 +114,6 @@ void LLUICtrl::initFromParams(const Params& p) } setTabStop(p.tab_stop); - setFocusLostCallback(p.focus_lost_callback()); if (p.initial_value.isProvided() && !p.control_name.isProvided()) @@ -800,14 +799,7 @@ namespace LLInitParam return false; } - template<> - bool ParamCompare::equals( - const LLUICtrl::focus_callback_t &a, - const LLUICtrl::focus_callback_t &b) - { - return false; - } - + template<> bool ParamCompare::equals( const LLUICtrl::enable_callback_t &a, diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 3add9393ea..0ca3acfa1c 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -124,8 +124,6 @@ public: Optional mouseenter_callback; Optional mouseleave_callback; - Optional focus_lost_callback; - Optional control_name; Optional enabled_controls; Optional controls_visibility; @@ -309,11 +307,6 @@ namespace LLInitParam const LLUICtrl::enable_callback_t &a, const LLUICtrl::enable_callback_t &b); - template<> - bool ParamCompare::equals( - const LLUICtrl::focus_callback_t &a, - const LLUICtrl::focus_callback_t &b); - template<> bool ParamCompare >::equals( const LLLazyValue &a, const LLLazyValue &b); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 256c776293..10cb3fb377 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -466,16 +466,6 @@ LLRect LLView::getRequiredRect() return mRect; } -//virtual -void LLView::onFocusLost() -{ -} - -//virtual -void LLView::onFocusReceived() -{ -} - BOOL LLView::focusNextRoot() { LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index bf3b5d0614..7a37d6f430 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -405,10 +405,6 @@ public: BOOL getSaveToXML() const { return mSaveToXML; } void setSaveToXML(BOOL b) { mSaveToXML = b; } - // inherited from LLFocusableElement - /* virtual */ void onFocusLost(); - /* virtual */ void onFocusReceived(); - typedef enum e_hit_test_type { HIT_TEST_USE_BOUNDING_RECT, diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 96c707b08f..4523267edd 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -125,8 +125,8 @@ BOOL LLChatBar::postBuild() mInputEditor = getChild("Chat Editor"); mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke, this); - mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this); - mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this ); + mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost)); + mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus)); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setRevertOnEsc( FALSE ); mInputEditor->setIgnoreTab(TRUE); @@ -538,14 +538,14 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) } // static -void LLChatBar::onInputEditorFocusLost( LLFocusableElement* caller, void* userdata) +void LLChatBar::onInputEditorFocusLost() { // stop typing animation gAgent.stopTyping(); } // static -void LLChatBar::onInputEditorGainFocus( LLFocusableElement* caller, void* userdata ) +void LLChatBar::onInputEditorGainFocus() { LLFloaterChat::setHistoryCursorAndScrollToEnd(); } diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index a41947218d..86aa3ebd2a 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -87,8 +87,8 @@ public: static void onTabClick( void* userdata ); static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); - static void onInputEditorFocusLost(LLFocusableElement* caller,void* userdata); - static void onInputEditorGainFocus(LLFocusableElement* caller,void* userdata); + static void onInputEditorFocusLost(); + static void onInputEditorGainFocus(); void onCommitGesture(LLUICtrl* ctrl); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index e5f5e8eedb..3fe7d8d9da 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -1043,7 +1043,7 @@ BOOL LLPanelLandObjects::postBuild() mSelectedObjects = getChild("selected_objects_text"); mCleanOtherObjectsTime = getChild("clean other time"); - mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus, this); + mCleanOtherObjectsTime->setFocusLostCallback(boost::bind(onLostFocus, _1, this)); mCleanOtherObjectsTime->setCommitCallback(onCommitClean, this); childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32); diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index fbc0ff3cf5..938370b732 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -106,7 +106,7 @@ BOOL LLFloaterPostcard::postBuild() childSetValue("name_form", LLSD(name_string)); // For the first time a user focusess to .the msg box, all text will be selected. - getChild("msg_form")->setFocusChangedCallback(onMsgFormFocusRecieved, this); + getChild("msg_form")->setFocusChangedCallback(boost::bind(onMsgFormFocusRecieved, _1, this)); childSetFocus("to_form", TRUE); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 2a29566120..d149c8bbb5 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1318,7 +1318,7 @@ void LLFolderView::startRenamingSelectedItem( void ) mRenamer->setVisible( TRUE ); // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); - mRenamer->setTopLostCallback(onRenamerLost); + mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1)); gFocusMgr.setTopCtrl( mRenamer ); } } @@ -2147,7 +2147,7 @@ void LLFolderView::updateRenamerPosition() ///---------------------------------------------------------------------------- //static -void LLFolderView::onRenamerLost( LLFocusableElement* renamer, void* user_data) +void LLFolderView::onRenamerLost( LLFocusableElement* renamer) { LLUICtrl* uictrl = dynamic_cast(renamer); if (uictrl) diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index a05dec3193..69c0c5b132 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -279,7 +279,7 @@ protected: LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. void commitRename( const LLSD& data ); - static void onRenamerLost( LLFocusableElement* renamer, void* user_data); + static void onRenamerLost( LLFocusableElement* renamer); void finishRenamingItem( void ); void closeRenamer( void ); diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 29102feb64..254e16e1fb 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -78,7 +78,7 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) } // LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im_session.xml"); - gFocusMgr.addFocusChangeCallback(boost::bind(&LLIMFloater::focusChangeCallback, this)); + LLUI::getRootView()->setFocusLostCallback(boost::bind(&LLIMFloater::focusChangeCallback, this)); mCloseSignal.connect(boost::bind(&LLIMFloater::onClose, this)); } @@ -177,8 +177,8 @@ BOOL LLIMFloater::postBuild() // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); + mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this) ); mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setRevertOnEsc( FALSE ); @@ -221,7 +221,7 @@ void* LLIMFloater::createPanelGroupControl(void* userdata) void LLIMFloater::focusChangeCallback() { // hide docked floater if user clicked inside in-world area - if (isDocked() && gFocusMgr.getKeyboardFocus() == NULL) + if (isDocked()) { setVisible(false); } diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index de4faf72f5..aa2beabf3d 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1086,10 +1086,7 @@ LLFloaterIMPanel::~LLFloaterIMPanel() mVoiceChannel = NULL; //delete focus lost callback - if(mInputEditor) - { - mInputEditor->setFocusLostCallback( NULL ); - } + mFocusCallbackConnection.disconnect(); } BOOL LLFloaterIMPanel::postBuild() @@ -1099,8 +1096,8 @@ BOOL LLFloaterIMPanel::postBuild() mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); mInputEditor = getChild("chat_editor"); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); + mFocusCallbackConnection = mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this)); mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); mInputEditor->setCommitCallback( onCommitChat, this ); mInputEditor->setCommitOnFocusLost( FALSE ); diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index dbf5e1cb6a..fd1134ee5e 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -357,6 +357,8 @@ private: // Timer to detect when user has stopped typing. LLFrameTimer mLastKeystrokeTimer; + boost::signals2::connection mFocusCallbackConnection; + void disableWhileSessionStarting(); }; diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 9d14a3fbdc..a6c2435e1e 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -190,7 +190,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.max_length_bytes(p.max_chars); params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.focus_lost_callback(NULL); params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index cec4b9f7c7..1d8789fde0 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -190,7 +190,7 @@ BOOL LLNearbyChatBar::postBuild() mChatBox->setCommitCallback(boost::bind(&LLNearbyChatBar::onChatBoxCommit, this)); mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this); - mChatBox->setFocusLostCallback(&onChatBoxFocusLost, this); + mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this)); mChatBox->setIgnoreArrowKeys(TRUE); mChatBox->setCommitOnFocusLost( FALSE ); diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index ee5d265220..7eaee92778 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -238,13 +238,13 @@ BOOL LLPanelClassified::postBuild() mNameEditor = getChild("given_name_editor"); mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN); mNameEditor->setCommitOnFocusLost(TRUE); - mNameEditor->setFocusReceivedCallback(focusReceived, this); + mNameEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mNameEditor->setCommitCallback(onCommitAny, this); mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII ); mDescEditor = getChild("desc_editor"); mDescEditor->setCommitOnFocusLost(TRUE); - mDescEditor->setFocusReceivedCallback(focusReceived, this); + mDescEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mDescEditor->setCommitCallback(onCommitAny, this); mLocationEditor = getChild("location_editor"); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index d63fd141b0..5eb7b8f5f5 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -99,8 +99,8 @@ BOOL LLPanelGroupGeneral::postBuild() if(mEditCharter) { mEditCharter->setCommitCallback(onCommitAny, this); - mEditCharter->setFocusReceivedCallback(onFocusEdit, this); - mEditCharter->setFocusChangedCallback(onFocusEdit, this); + mEditCharter->setFocusReceivedCallback(boost::bind(onFocusEdit, _1, this)); + mEditCharter->setFocusChangedCallback(boost::bind(onFocusEdit, _1, this)); } diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 378a09e315..99bb760b61 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1730,7 +1730,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) mRoleDescription->setCommitOnFocusLost(TRUE); mRoleDescription->setCommitCallback(onDescriptionCommit, this); - mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this); + mRoleDescription->setFocusReceivedCallback(boost::bind(onDescriptionFocus, _1, this)); setFooterEnabled(FALSE); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 150fd399c6..809e1852f4 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -229,7 +229,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLComboBox* server_choice_combo = sInstance->getChild("server_combo"); server_choice_combo->setCommitCallback(onSelectServer, NULL); - server_choice_combo->setFocusLostCallback(onServerComboLostFocus); + server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); childSetAction("connect_btn", onClickConnect, this); @@ -973,7 +973,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) loadLoginPage(); } -void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) +void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) { if (!sInstance) return; diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index ffcf6a9b70..5692b8d345 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -94,7 +94,7 @@ private: static void onClickForgotPassword(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); - static void onServerComboLostFocus(LLFocusableElement*, void*); + static void onServerComboLostFocus(LLFocusableElement*); private: LLPointer mLogoImage; -- cgit v1.2.3 From a3ba111e39be0bfa0278dfce66f4608fac7c0aa2 Mon Sep 17 00:00:00 2001 From: Eric Tulla Date: Wed, 30 Sep 2009 16:05:41 +0000 Subject: Cherry pick of simple fix for duplicate inventory folders (one non working) in some inventory panel views. Result of: svn merge -c 134827 svn+ssh://svn.lindenlab.com/svn/linden/branches/avatar-pipeline/currently-worn-folder-10 . --- indra/newview/llfloaterinventory.cpp | 9 ++++++--- indra/newview/llfloaterinventory.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 27eb12b9cc..116286329c 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1169,7 +1169,8 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) mScroller(NULL), mSortOrderSetting(p.sort_order_setting), mInventory(p.inventory), - mAllowMultiSelect(p.allow_multi_select) + mAllowMultiSelect(p.allow_multi_select), + mHasInventoryConnection(false) { // contex menu callbacks mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); @@ -1230,9 +1231,10 @@ BOOL LLInventoryPanel::postBuild() mInventoryObserver = new LLInventoryPanelObserver(this); mInventory->addObserver(mInventoryObserver); // build view of inventory if inventory ready, otherwise wait for modelChanged() callback - if (mInventory->isInventoryUsable()) + if (mInventory->isInventoryUsable() && !mHasInventoryConnection) { rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); + mHasInventoryConnection = true; } // bit of a hack to make sure the inventory is open. @@ -1332,9 +1334,10 @@ void LLInventoryPanel::modelChanged(U32 mask) bool handled = false; // inventory just initialized, do complete build - if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty()) + if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) { rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); + mHasInventoryConnection = true; return; } diff --git a/indra/newview/llfloaterinventory.h b/indra/newview/llfloaterinventory.h index a40efe020b..1aaac74c87 100644 --- a/indra/newview/llfloaterinventory.h +++ b/indra/newview/llfloaterinventory.h @@ -179,6 +179,7 @@ protected: LLScrollContainer* mScroller; BOOL mAllowMultiSelect; std::string mSortOrderSetting; + bool mHasInventoryConnection; }; class LLFloaterInventory; -- cgit v1.2.3 From feabeb496518f28359f654fdc397354355743589 Mon Sep 17 00:00:00 2001 From: Adam Moss Date: Wed, 30 Sep 2009 17:46:31 +0000 Subject: DEV-35039 Viewer 2.0 Help System - Viewer Development svn merge -r134800:134805 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer2help-3 --- indra/llui/CMakeLists.txt | 2 +- indra/llui/llbutton.cpp | 45 +++--- indra/llui/llbutton.h | 7 +- indra/llui/llfloater.cpp | 129 ++++++---------- indra/llui/llfloater.h | 14 +- indra/llui/llhelp.h | 45 ++++++ indra/llui/llpanel.cpp | 3 + indra/llui/llpanel.h | 8 +- indra/llui/llui.cpp | 53 +------ indra/llui/llui.h | 7 +- indra/llui/lluictrl.cpp | 21 +++ indra/llui/lluictrl.h | 4 + indra/llui/llurlaction.cpp | 1 - indra/newview/CMakeLists.txt | 10 +- indra/newview/app_settings/settings.xml | 20 +-- indra/newview/llappviewer.cpp | 6 +- indra/newview/llfloaterchat.cpp | 1 - indra/newview/llfloaterhelpbrowser.cpp | 138 +++++++++++++++++ indra/newview/llfloaterhelpbrowser.h | 72 +++++++++ indra/newview/llfloatermediabrowser.cpp | 71 +-------- indra/newview/llfloatermediabrowser.h | 18 +-- indra/newview/llfloaterreporter.cpp | 41 +---- indra/newview/llfloaterreporter.h | 6 +- indra/newview/llmediactrl.cpp | 11 +- indra/newview/llpanellogin.cpp | 6 +- indra/newview/llpreviewscript.cpp | 104 ++++++------- indra/newview/llpreviewscript.h | 4 - indra/newview/llstartup.cpp | 11 ++ indra/newview/llurldispatcher.cpp | 17 +-- indra/newview/llviewerfloaterreg.cpp | 9 +- indra/newview/llviewerhelp.cpp | 125 ++++++++++++++++ indra/newview/llviewerhelp.h | 65 ++++++++ indra/newview/llviewerhelputil.cpp | 114 ++++++++++++++ indra/newview/llviewerhelputil.h | 49 ++++++ indra/newview/llviewermenu.cpp | 30 +--- indra/newview/llviewerparcelmgr.cpp | 1 - .../default/html/en-us/help-offline/index.html | 29 ++++ indra/newview/skins/default/textures/textures.xml | 14 +- .../textures/windows/Icon_Restore_Foreground.png | Bin 0 -> 2955 bytes .../textures/windows/Icon_Restore_Press.png | Bin 0 -> 2971 bytes .../newview/skins/default/xui/en/floater_about.xml | 1 + .../skins/default/xui/en/floater_help_browser.xml | 165 ++------------------- indra/newview/skins/default/xui/en/menu_viewer.xml | 18 --- .../newview/skins/default/xui/en/notifications.xml | 62 -------- .../skins/default/xui/en/panel_script_ed.xml | 4 +- .../default/xui/en/panel_side_tray_tab_caption.xml | 13 ++ indra/newview/skins/default/xui/en/strings.xml | 1 - indra/newview/tests/llviewerhelputil_test.cpp | 127 ++++++++++++++++ 48 files changed, 1005 insertions(+), 697 deletions(-) create mode 100644 indra/llui/llhelp.h create mode 100644 indra/newview/llfloaterhelpbrowser.cpp create mode 100644 indra/newview/llfloaterhelpbrowser.h create mode 100644 indra/newview/llviewerhelp.cpp create mode 100644 indra/newview/llviewerhelp.h create mode 100644 indra/newview/llviewerhelputil.cpp create mode 100644 indra/newview/llviewerhelputil.h create mode 100644 indra/newview/skins/default/html/en-us/help-offline/index.html create mode 100644 indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png create mode 100644 indra/newview/skins/default/textures/windows/Icon_Restore_Press.png create mode 100644 indra/newview/tests/llviewerhelputil_test.cpp diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 1e6b216a61..d7d411dee6 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -129,7 +129,7 @@ set(llui_HEADER_FILES llfocusmgr.h llfunctorregistry.h llhandle.h - llhtmlhelp.h + llhelp.h lliconctrl.h llkeywords.h lllayoutstack.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index fa13ced037..b9613b502c 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -39,7 +39,6 @@ #include "llstring.h" // Project includes -#include "llhtmlhelp.h" #include "llkeyboard.h" #include "llui.h" #include "lluiconstants.h" @@ -49,8 +48,10 @@ #include "llfloaterreg.h" #include "llfocusmgr.h" #include "llwindow.h" +#include "llnotifications.h" #include "llrender.h" #include "lluictrlfactory.h" +#include "llhelp.h" static LLDefaultChildRegistry::Register r("button"); @@ -92,7 +93,6 @@ LLButton::Params::Params() mouse_held_callback("mouse_held_callback"), is_toggle("is_toggle", false), scale_image("scale_image", true), - help_url("help_url"), hover_glow_amount("hover_glow_amount"), commit_on_return("commit_on_return", true), picture_style("picture_style", false) @@ -173,11 +173,6 @@ LLButton::LLButton(const LLButton::Params& p) mMouseDownTimer.stop(); - if (p.help_url.isProvided()) - { - setHelpURLCallback(p.help_url); - } - // if custom unselected button image provided... if (p.image_unselected != default_params.image_unselected) { @@ -1034,24 +1029,6 @@ void LLButton::addImageAttributeToXML(LLXMLNodePtr node, } } -void clicked_help(void* data) -{ - LLButton* self = (LLButton*)data; - if (!self) return; - - if (!LLUI::sHtmlHelp) - { - return; - } - - LLUI::sHtmlHelp->show(self->getHelpURL()); -} - -void LLButton::setHelpURLCallback(const std::string &help_url) -{ - mHelpURL = help_url; - setClickedCallback(clicked_help,this); -} // static void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) @@ -1077,6 +1054,24 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname)); } +// static +void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname) +{ + // search back through the button's parents for a panel + // with a help_topic string defined + std::string help_topic; + if (LLUI::sHelpImpl && + ctrl->findHelpTopic(help_topic)) + { + LLUI::sHelpImpl->showTopic(help_topic); + return; // success + } + + // display an error if we can't find a help_topic string. + // fix this by adding a help_topic attribute to the xui file + LLNotifications::instance().add("UnableToFindHelpTopic"); +} + void LLButton::resetMouseDownTimer() { mMouseDownTimer.stop(); diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 06e1dac914..04716d605b 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -118,7 +118,6 @@ public: commit_on_return, picture_style; //if true, don't display label - Optional help_url; Optional hover_glow_amount; Optional held_down_delay; @@ -230,12 +229,10 @@ public: void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } - void setHelpURLCallback(const std::string &help_url); - const std::string& getHelpURL() const { return mHelpURL; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + static void showHelp(LLUICtrl* ctrl, const LLSD& sdname); protected: const LLPointer& getImageUnselected() const { return mImageUnselected; } @@ -314,8 +311,6 @@ private: BOOL mCommitOnReturn; BOOL mFadeWhenDisabled; - std::string mHelpURL; - LLFrameTimer mFlashingTimer; }; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 81915731c3..ff0288a32f 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -59,6 +59,7 @@ #include "lltabcontainer.h" #include "v2math.h" #include "lltrans.h" +#include "llhelp.h" #include "llmultifloater.h" // use this to control "jumping" behavior when Ctrl-Tabbing @@ -66,48 +67,35 @@ const S32 TABBED_FLOATER_OFFSET = 0; std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = { - "Icon_Close_Foreground", //BUTTON_CLOSE - "restore.tga", //BUTTON_RESTORE - "minimize.tga", //BUTTON_MINIMIZE - "tearoffbox.tga", //BUTTON_TEAR_OFF - "closebox.tga", //BUTTON_EDIT - "Icon_Dock_Foreground", - "Icon_Undock_Foreground" -}; - -// Empty string means programmatic glow effect, achieved by -// not setting explicit image. -std::string LLFloater::sButtonHoveredImageNames[BUTTON_COUNT] = -{ - "", //BUTTON_CLOSE - "restore_pressed.tga", //BUTTON_RESTORE - "minimize_pressed.tga", //BUTTON_MINIMIZE - "tearoff_pressed.tga", //BUTTON_TEAR_OFF - "close_in_blue.tga", //BUTTON_EDIT - "", //BUTTON_DOCK - "", //BUTTON_UNDOCK + "Icon_Close_Foreground", //BUTTON_CLOSE + "Icon_Restore_Foreground", //BUTTON_RESTORE + "Icon_Minimize_Foreground", //BUTTON_MINIMIZE + "tearoffbox.tga", //BUTTON_TEAR_OFF + "Icon_Dock_Foreground", //BUTTON_DOCK + "Icon_Undock_Foreground", //BUTTON_UNDOCK + "Icon_Help_Foreground" //BUTTON_HELP }; std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = { - "Icon_Close_Press", //BUTTON_CLOSE - "restore_pressed.tga", //BUTTON_RESTORE - "minimize_pressed.tga", //BUTTON_MINIMIZE - "tearoff_pressed.tga", //BUTTON_TEAR_OFF - "close_in_blue.tga", //BUTTON_EDIT - "Icon_Dock_Press", - "Icon_Undock_Press" + "Icon_Close_Press", //BUTTON_CLOSE + "Icon_Restore_Press", //BUTTON_RESTORE + "Icon_Minimize_Press", //BUTTON_MINIMIZE + "tearoff_pressed.tga", //BUTTON_TEAR_OFF + "Icon_Dock_Press", //BUTTON_DOCK + "Icon_Undock_Press", //BUTTON_UNDOCK + "Icon_Help_Press" //BUTTON_HELP }; std::string LLFloater::sButtonNames[BUTTON_COUNT] = { - "llfloater_close_btn", //BUTTON_CLOSE + "llfloater_close_btn", //BUTTON_CLOSE "llfloater_restore_btn", //BUTTON_RESTORE "llfloater_minimize_btn", //BUTTON_MINIMIZE "llfloater_tear_off_btn", //BUTTON_TEAR_OFF - "llfloater_edit_btn", //BUTTON_EDIT - "llfloater_dock_btn", - "llfloater_undock_btn" + "llfloater_dock_btn", //BUTTON_DOCK + "llfloater_undock_btn", //BUTTON_UNDOCK + "llfloater_help_btn" //BUTTON_HELP }; std::string LLFloater::sButtonToolTips[BUTTON_COUNT]; @@ -122,9 +110,9 @@ std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF - "BUTTON_EDIT", //"Edit", //BUTTON_EDIT "BUTTON_DOCK", - "BUTTON_UNDOCK" + "BUTTON_UNDOCK", + "BUTTON_HELP" }; LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = @@ -133,13 +121,12 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = LLFloater::onClickMinimize, //BUTTON_RESTORE LLFloater::onClickMinimize, //BUTTON_MINIMIZE LLFloater::onClickTearOff, //BUTTON_TEAR_OFF - LLFloater::onClickEdit, //BUTTON_EDIT - LLFloater::onClickDock, - LLFloater::onClickDock + LLFloater::onClickDock, //BUTTON_DOCK + LLFloater::onClickDock, //BUTTON_UNDOCK + LLFloater::onClickHelp //BUTTON_HELP }; LLMultiFloater* LLFloater::sHostp = NULL; -BOOL LLFloater::sEditModeEnabled = FALSE; BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting LLFloater::handle_map_t LLFloater::sFloaterMap; @@ -259,7 +246,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mMinimized(FALSE), mForeground(FALSE), mFirstLook(TRUE), - mEditing(FALSE), mButtonScale(1.0f), mAutoFocus(TRUE), // automatically take focus when opened mCanDock(false), @@ -314,6 +300,12 @@ void LLFloater::initFloater() mButtonsEnabled[BUTTON_CLOSE] = TRUE; } + // Help button: '?' + if ( !mHelpTopic.empty() ) + { + mButtonsEnabled[BUTTON_HELP] = TRUE; + } + // Minimize button only for top draggers if ( !mDragOnLeft && mCanMinimize ) { @@ -804,7 +796,7 @@ void LLFloater::setTitle( const std::string& title ) applyTitle(); } -std::string LLFloater::getTitle() +std::string LLFloater::getTitle() const { if (mTitle.empty()) { @@ -822,7 +814,7 @@ void LLFloater::setShortTitle( const std::string& short_title ) applyTitle(); } -std::string LLFloater::getShortTitle() +std::string LLFloater::getShortTitle() const { if (mShortTitle.empty()) { @@ -834,8 +826,6 @@ std::string LLFloater::getShortTitle() } } - - BOOL LLFloater::canSnapTo(const LLView* other_view) { if (NULL == other_view) @@ -1051,6 +1041,10 @@ void LLFloater::setMinimized(BOOL minimize) reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); } + // don't show the help button while minimized - it's + // not very useful when minimized and uses up space + mButtonsEnabled[BUTTON_HELP] = !minimize; + applyTitle (); make_ui_sound("UISndWindowClose"); @@ -1387,28 +1381,6 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock) } } -//static -void LLFloater::setEditModeEnabled(BOOL enable) -{ - if (enable != sEditModeEnabled) - { - S32 count = 0; - for(handle_map_iter_t iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter) - { - LLFloater* floater = iter->second; - if (!floater->isDead()) - { - iter->second->mButtonsEnabled[BUTTON_EDIT] = enable; - iter->second->updateButtons(); - } - count++; - } - } - - sEditModeEnabled = enable; -} - - // static void LLFloater::onClickMinimize(LLFloater* self) { @@ -1456,19 +1428,20 @@ void LLFloater::onClickTearOff(LLFloater* self) } // static -void LLFloater::onClickEdit(LLFloater* self) +void LLFloater::onClickDock(LLFloater* self) { - if (!self) - return; - self->mEditing = self->mEditing ? FALSE : TRUE; + if(self && self->mCanDock) + { + self->setDocked(!self->mDocked, true); + } } // static -void LLFloater::onClickDock(LLFloater* self) +void LLFloater::onClickHelp( LLFloater* self ) { - if(self && self->mCanDock) + if (self && LLUI::sHelpImpl) { - self->setDocked(!self->mDocked, true); + LLUI::sHelpImpl->showTopic(self->getHelpTopic()); } } @@ -1807,17 +1780,9 @@ void LLFloater::buildButtons() // Selected, no matter if hovered or not, is "pressed" p.image_selected.name(sButtonPressedImageNames[i]); p.image_hover_selected.name(sButtonPressedImageNames[i]); - // Empty string means programmatic glow effect, achieved by - // not setting explicit image. - if (sButtonHoveredImageNames[i].empty()) - { - // These icons are really small, need glow amount increased - p.hover_glow_amount( 0.22f ); - } - else - { - p.image_hover_unselected.name(sButtonHoveredImageNames[i]); - } + // Use a glow effect when the user hovers over the button + // These icons are really small, need glow amount increased + p.hover_glow_amount( 0.33f ); p.click_callback.function(boost::bind(sButtonCallbacks[i], this)); p.tab_stop(false); p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 513f6a6918..2a31ba4e8f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -101,9 +101,9 @@ public: BUTTON_RESTORE, BUTTON_MINIMIZE, BUTTON_TEAR_OFF, - BUTTON_EDIT, BUTTON_DOCK, BUTTON_UNDOCK, + BUTTON_HELP, BUTTON_COUNT }; @@ -173,9 +173,9 @@ public: void applyTitle(); const std::string& getCurrentTitle() const; void setTitle( const std::string& title); - std::string getTitle(); + std::string getTitle() const; void setShortTitle( const std::string& short_title ); - std::string getShortTitle(); + std::string getShortTitle() const; void setTitleVisible(bool visible); virtual void setMinimized(BOOL b); void moveResizeHandlesToFront(); @@ -256,12 +256,10 @@ public: static void onClickClose(LLFloater* floater); static void onClickMinimize(LLFloater* floater); static void onClickTearOff(LLFloater* floater); - static void onClickEdit(LLFloater* floater); static void onClickDock(LLFloater* floater); + static void onClickHelp(LLFloater* floater); static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } - static void setEditModeEnabled(BOOL enable); - static BOOL getEditModeEnabled() { return sEditModeEnabled; } static LLMultiFloater* getFloaterHost() {return sHostp; } protected: @@ -331,7 +329,6 @@ private: BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. - BOOL mEditing; typedef std::set > handle_set_t; typedef std::set >::iterator handle_set_iter_t; @@ -350,11 +347,8 @@ private: bool mDocked; static LLMultiFloater* sHostp; - static BOOL sEditModeEnabled; static BOOL sQuitting; static std::string sButtonActiveImageNames[BUTTON_COUNT]; - // Images to use when cursor hovered over an enabled button - static std::string sButtonHoveredImageNames[BUTTON_COUNT]; static std::string sButtonPressedImageNames[BUTTON_COUNT]; static std::string sButtonNames[BUTTON_COUNT]; static std::string sButtonToolTips[BUTTON_COUNT]; diff --git a/indra/llui/llhelp.h b/indra/llui/llhelp.h new file mode 100644 index 0000000000..c06d29a4bd --- /dev/null +++ b/indra/llui/llhelp.h @@ -0,0 +1,45 @@ +/** + * @file llhelp.h + * @brief Abstract interface to the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLHELP_H +#define LL_LLHELP_H + +class LLHelp +{ + public: + virtual void showTopic(const std::string &topic) = 0; + // return default (fallback) topic name suitable for showTopic() + virtual std::string defaultTopic() = 0; +}; + +#endif // headerguard diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 26136e0a23..b9bbb4db22 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -80,6 +80,7 @@ LLPanel::Params::Params() strings("string"), filename("filename"), class_name("class"), + help_topic("help_topic"), visible_callback("visible_callback") { name = "panel"; @@ -98,6 +99,7 @@ LLPanel::LLPanel(const LLPanel::Params& p) mDefaultBtn(NULL), mBorder(NULL), mLabel(p.label), + mHelpTopic(p.help_topic), mCommitCallbackRegistrar(false), mEnableCallbackRegistrar(false), mXMLFilename(p.filename) @@ -416,6 +418,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p) } setLabel(p.label()); + setHelpTopic(p.help_topic); setShape(p.rect); parseFollowsFlags(p); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 81b5b68f05..8b23ea7030 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -83,6 +83,7 @@ public: Optional filename; Optional class_name; + Optional help_topic; Multiple strings; @@ -139,10 +140,11 @@ public: void updateDefaultBtn(); void setLabel(const LLStringExplicit& label) { mLabel = label; } std::string getLabel() const { return mLabel; } + void setHelpTopic(const std::string& help_topic) { mHelpTopic = help_topic; } + std::string getHelpTopic() const { return mHelpTopic; } void setCtrlsEnabled(BOOL b); - LLHandle getHandle() const { return mPanelHandle; } const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } @@ -243,6 +245,8 @@ protected: EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar; commit_signal_t mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD() + + std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer private: LLUIColor mBgColorAlpha; @@ -259,7 +263,7 @@ private: // for setting the xml filename when building panel in context dependent cases std::string mXMLFilename; - + }; // end class LLPanel #endif diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 000e85f78c..d5b67f53b7 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -79,10 +79,10 @@ std::list gUntranslated; /*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL; /*static*/ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f); /*static*/ LLWindow* LLUI::sWindow = NULL; -/*static*/ LLHtmlHelp* LLUI::sHtmlHelp = NULL; /*static*/ LLView* LLUI::sRootView = NULL; -/*static*/ BOOL LLUI::sDirty = FALSE; -/*static*/ LLRect LLUI::sDirtyRect; +/*static*/ BOOL LLUI::sDirty = FALSE; +/*static*/ LLRect LLUI::sDirtyRect; +/*static*/ LLHelp* LLUI::sHelpImpl = NULL; /*static*/ std::vector LLUI::sXUIPaths; /*static*/ LLFrameTimer LLUI::sMouseIdleTimer; @@ -695,44 +695,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre } -void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) -{ - if (NULL == image) - { - llwarns << "image == NULL; aborting function" << llendl; - return; - } - - LLGLSUIDefault gls_ui; - - gGL.pushMatrix(); - { - gGL.translatef((F32)x, (F32)y, 0.f); - - gGL.getTexUnit(0)->bind(image); - - gGL.color4fv(color.mV); - - gGL.begin(LLRender::QUADS); - { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2i(width, height ); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2i(0, height ); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2i(0, 0); - - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2i(width, 0); - } - gGL.end(); - } - gGL.popMatrix(); -} - - void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase ) { phase = fmod(phase, 1.f); @@ -1592,6 +1554,9 @@ void LLUI::initClass(const settings_map_t& settings, // Button initialization callback for toggle buttons LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); + // Display the help topic for the current context + LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2)); + // Currently unused, but kept for reference: LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); @@ -1850,12 +1815,6 @@ LLPointer LLUI::getUIImage(const std::string& name) return NULL; } -// static -void LLUI::setHtmlHelp(LLHtmlHelp* html_help) -{ - LLUI::sHtmlHelp = html_help; -} - LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) { for (settings_map_t::iterator itor = sSettingGroups.begin(); diff --git a/indra/llui/llui.h b/indra/llui/llui.h index fddf8192ad..86cb516500 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -57,13 +57,13 @@ #include "llfontgl.h" class LLColor4; -class LLHtmlHelp; class LLVector3; class LLVector2; class LLUIImage; class LLUUID; class LLWindow; class LLView; +class LLHelp; // UI colors extern const LLColor4 UI_VERTEX_COLOR; @@ -104,8 +104,6 @@ void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LL void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); -// Flip vertical, used for LLFloaterHTML -void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom); void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); @@ -203,7 +201,6 @@ public: static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); static void screenRectToGL(const LLRect& screen, LLRect *gl); static void glRectToScreen(const LLRect& gl, LLRect *screen); - static void setHtmlHelp(LLHtmlHelp* html_help); // Returns the control group containing the control name, or the default group static LLControlGroup& getControlControlGroup (const std::string& controlname); static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); } @@ -223,8 +220,8 @@ public: static LLUIAudioCallback sAudioCallback; static LLVector2 sGLScaleFactor; static LLWindow* sWindow; - static LLHtmlHelp* sHtmlHelp; static LLView* sRootView; + static LLHelp* sHelpImpl; private: static LLImageProviderInterface* sImageProvider; static std::vector sXUIPaths; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 2cd9c8844e..fe99d9c267 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -762,6 +762,27 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const return NULL; } +bool LLUICtrl::findHelpTopic(std::string& help_topic_out) +{ + LLUICtrl* ctrl = this; + + // search back through the control's parents for a panel + // with a help_topic string defined + while (ctrl) + { + LLPanel *panel = dynamic_cast(ctrl); + if (panel && !panel->getHelpTopic().empty()) + { + help_topic_out = panel->getHelpTopic(); + return true; // success + } + + ctrl = ctrl->getParentUICtrl(); + } + + return false; // no help topic found +} + // *TODO: Deprecate; for backwards compatability only: boost::signals2::connection LLUICtrl::setCommitCallback( boost::function cb, void* data) { diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 0ca3acfa1c..c2502732f3 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -223,6 +223,10 @@ public: LLUICtrl* getParentUICtrl() const; + // return true if help topic found by crawling through parents - + // topic then put in help_topic_out + bool findHelpTopic(std::string& help_topic_out); + boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); } boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); } diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 3b689b93c0..f3401f91f7 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -134,4 +134,3 @@ void LLUrlAction::copyLabelToClipboard(std::string url) LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); } } - diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e4e4d8a2fa..b74f67e72e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -169,9 +169,8 @@ set(viewer_SOURCE_FILES llfloatergroups.cpp llfloaterhandler.cpp llfloaterhardwaresettings.cpp - llfloaterhtmlcurrency.cpp + llfloaterhelpbrowser.cpp llfloatermediabrowser.cpp - llfloaterhtmlsimple.cpp llfloaterhud.cpp llfloaterimagepreview.cpp llfloaterinspect.cpp @@ -426,6 +425,8 @@ set(viewer_SOURCE_FILES llviewerfloaterreg.cpp llviewergenericmessage.cpp llviewergesture.cpp + llviewerhelp.cpp + llviewerhelputil.cpp llviewerinventory.cpp llviewerjointattachment.cpp llviewerjoint.cpp @@ -632,9 +633,8 @@ set(viewer_HEADER_FILES llfloatergroups.h llfloaterhandler.h llfloaterhardwaresettings.h - llfloaterhtmlcurrency.h + llfloaterhelpbrowser.h llfloatermediabrowser.h - llfloaterhtmlsimple.h llfloaterhud.h llfloaterimagepreview.h llfloaterinspect.h @@ -891,6 +891,7 @@ set(viewer_HEADER_FILES llviewerfloaterreg.h llviewergenericmessage.h llviewergesture.h + llviewerhelp.h llviewerinventory.h llviewerjoint.h llviewerjointattachment.h @@ -1526,6 +1527,7 @@ endif (INSTALL) include(LLAddBuildTest) SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp + llviewerhelputil.cpp ) set_source_files_properties( ${viewer_TEST_SOURCE_FILES} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 19d503390c..8cbe6d20c6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3542,28 +3542,28 @@ S32 Value 400 - - HelpHomeURL + + HelpUseLocal Comment - URL of initial help page + If set, always use this for help: skins/default/html/[LANGUAGE]/help-offline/index.html Persist - 1 + 0 Type - String + Boolean Value - help/index.html + 0 - HelpLastVisitedURL + HelpURLFormat Comment - URL of last help page, will be shown next time help is accessed + URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments Persist - 1 + 0 Type String Value - help/index.html + http://www.google.com/search?q=site%3Awiki.secondlife.com+[TOPIC]&ignore_channel=[CHANNEL]&ignore_version=[VERSION]&ignore_os=[OS]&ignore_language=[LANGUAGE]&ignore_version_major=[VERSION_MAJOR]&ignore_version_minor=[VERSION_MINOR]&ignore_version_patch=[VERSION_PATCH]&ignore_version_build=[VERSION_BUILD] HighResSnapshot diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 355660faa5..30e0a5770c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -67,6 +67,7 @@ #include "llviewerobjectlist.h" #include "llworldmap.h" #include "llmutelist.h" +#include "llviewerhelp.h" #include "lluicolortable.h" #include "llurldispatcher.h" #include "llurlhistory.h" @@ -663,8 +664,6 @@ bool LLAppViewer::init() mNumSessions++; gSavedSettings.setS32("NumSessions", mNumSessions); - gSavedSettings.setString("HelpLastVisitedURL",gSavedSettings.getString("HelpHomeURL")); - if (gSavedSettings.getBOOL("VerboseLogs")) { LLError::setPrintLocation(true); @@ -694,6 +693,9 @@ bool LLAppViewer::init() LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal); LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + // Let code in llui access the viewer help floater + LLUI::sHelpImpl = LLViewerHelp::getInstance(); + // Set the link color for any Urls in text fields LLTextBase::setLinkColor( LLUIColorTable::instance().getColor("HTMLLinkColor") ); diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 14fb93df61..ca43f41d05 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -66,7 +66,6 @@ #include "lllogchat.h" #include "lltexteditor.h" #include "lltextparser.h" -#include "llfloaterhtml.h" #include "llweb.h" #include "llstylemap.h" diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp new file mode 100644 index 0000000000..d67b26d36c --- /dev/null +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -0,0 +1,138 @@ +/** + * @file llfloaterhelpbrowser.cpp + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterhelpbrowser.h" + +#include "llfloaterreg.h" +#include "llpluginclassmedia.h" +#include "llmediactrl.h" +#include "llviewerwindow.h" +#include "llviewercontrol.h" +#include "llweb.h" +#include "llui.h" + +#include "llurlhistory.h" +#include "llmediactrl.h" +#include "llviewermedia.h" + + +LLFloaterHelpBrowser::LLFloaterHelpBrowser(const LLSD& key) + : LLFloater(key) +{ + // really really destroy the help browser when it's closed, it'll be recreated. + // *TODO: when onClose() is resurrected as a virtual, this bind can go away. + mCloseSignal.connect(boost::bind(&LLFloaterHelpBrowser::onClose, this)); +} + +BOOL LLFloaterHelpBrowser::postBuild() +{ + mBrowser = getChild("browser"); + mBrowser->addObserver(this); + + childSetAction("open_browser", onClickOpenWebBrowser, this); + + buildURLHistory(); + return TRUE; +} + +void LLFloaterHelpBrowser::buildURLHistory() +{ + // Get all of the entries in the "browser" collection + LLSD browser_history = LLURLHistory::getURLHistory("browser"); + + // initialize URL history in the plugin + mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); +} + +void LLFloaterHelpBrowser::onClose() +{ + destroy(); // really destroy this dialog on closure, it's relatively heavyweight. +} + +void LLFloaterHelpBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if(event == MEDIA_EVENT_LOCATION_CHANGED) + { + setCurrentURL(self->getLocation()); + } + else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // nothing yet + } +} + +void LLFloaterHelpBrowser::setCurrentURL(const std::string& url) +{ + mCurrentURL = url; + + // redirects will navigate momentarily to about:blank, don't add to history + if (mCurrentURL != "about:blank") + { + // Serialize url history + LLURLHistory::removeURL("browser", mCurrentURL); + LLURLHistory::addURL("browser", mCurrentURL); + } +} + +//static +void LLFloaterHelpBrowser::onClickClose(void* user_data) +{ + LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data; + + self->closeFloater(); +} + +//static +void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data) +{ + LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data; + + std::string url = self->mCurrentURL.empty() ? + self->mBrowser->getHomePageUrl() : + self->mCurrentURL; + LLWeb::loadURLExternal(url); +} + +void LLFloaterHelpBrowser::openMedia(const std::string& media_url) +{ + mBrowser->setHomePageUrl(media_url); + //mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:
" + media_url + ""); // tofu HACK for debugging =:) + mBrowser->navigateTo(media_url); + setCurrentURL(media_url); +} + +void LLFloaterHelpBrowser::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) +{ + mBrowser->navigateToLocalPage(subdir, filename_in); +} diff --git a/indra/newview/llfloaterhelpbrowser.h b/indra/newview/llfloaterhelpbrowser.h new file mode 100644 index 0000000000..14a276b428 --- /dev/null +++ b/indra/newview/llfloaterhelpbrowser.h @@ -0,0 +1,72 @@ +/** + * @file llfloatermediabrowser.h + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERHELPBROWSER_H +#define LL_LLFLOATERHELPBROWSER_H + +#include "llfloater.h" +#include "llmediactrl.h" + + +class LLMediaCtrl; + +class LLFloaterHelpBrowser : + public LLFloater, + public LLViewerMediaObserver +{ + public: + LLFloaterHelpBrowser(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + void onClose(); + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + void openMedia(const std::string& media_url); + + void navigateToLocalPage( const std::string& subdir, const std::string& filename_in ); + + private: + void buildURLHistory(); + void setCurrentURL(const std::string& url); + + static void onClickClose(void* user_data); + static void onClickOpenWebBrowser(void* user_data); + + private: + LLMediaCtrl* mBrowser; + std::string mCurrentURL; +}; + +#endif // LL_LLFLOATERHELPBROWSER_H + diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index c580cdef8a..c7ec4bd585 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -1,6 +1,6 @@ /** - * @file llfloaterhtmlhelp.cpp - * @brief HTML Help floater - uses embedded web browser control + * @file llfloatermediabrowser.cpp + * @brief media browser floater - uses embedded media browser control * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -33,7 +33,6 @@ #include "llviewerprecompiledheaders.h" #include "llfloatermediabrowser.h" -#include "llfloaterhtml.h" #include "llfloaterreg.h" #include "llparcel.h" @@ -330,69 +329,3 @@ void LLFloaterMediaBrowser::openMedia(const std::string& media_url) mBrowser->navigateTo(media_url); setCurrentURL(media_url); } -//////////////////////////////////////////////////////////////////////////////// -// - -LLViewerHtmlHelp gViewerHtmlHelp; - - -//////////////////////////////////////////////////////////////////////////////// -// -LLViewerHtmlHelp::LLViewerHtmlHelp() -{ - - LLUI::setHtmlHelp(this); -} - -LLViewerHtmlHelp::~LLViewerHtmlHelp() -{ - - LLUI::setHtmlHelp(NULL); -} - -void LLViewerHtmlHelp::show() -{ - show(""); -} - -void LLViewerHtmlHelp::show(std::string url) -{ - LLFloaterMediaBrowser* floater_html = dynamic_cast(LLFloaterReg::getInstance("media_browser")); - floater_html->setVisible(FALSE); - - if (url.empty()) - { - url = floater_html->getSupportURL(); - } - - if (gSavedSettings.getBOOL("UseExternalBrowser")) - { - LLSD notificationData; - notificationData["url"] = url; - - LLNotifications::instance().add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL); - floater_html->closeFloater(); - } - else - { - // don't wait, just do it - floater_html->setVisible(TRUE); - floater_html->openMedia(url); - } -} - -// static -bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) -{ - LLFloaterMediaBrowser* floater_html = dynamic_cast(LLFloaterReg::getInstance("media_browser")); - floater_html->setVisible(FALSE); - std::string url = floater_html->getSupportURL(); - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - LLWeb::loadURL(url); - } - floater_html->closeFloater(); - return false; -} - diff --git a/indra/newview/llfloatermediabrowser.h b/indra/newview/llfloatermediabrowser.h index 76e8b517a0..c315f9e797 100644 --- a/indra/newview/llfloatermediabrowser.h +++ b/indra/newview/llfloatermediabrowser.h @@ -1,6 +1,6 @@ /** * @file llfloatermediabrowser.h - * @brief HTML Help floater - uses embedded web browser control + * @brief media browser floater - uses embedded media browser control * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -33,23 +33,9 @@ #ifndef LL_LLFLOATERMEDIABROWSER_H #define LL_LLFLOATERMEDIABROWSER_H -#include "llhtmlhelp.h" #include "llfloater.h" #include "llmediactrl.h" -class LLViewerHtmlHelp : public LLHtmlHelp -{ -public: - LLViewerHtmlHelp(); - virtual ~LLViewerHtmlHelp(); - - /*virtual*/ void show(); - /*virtual*/ void show(std::string start_url); - void show(std::string start_url, std::string title); - - static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); - -}; class LLComboBox; class LLMediaCtrl; @@ -93,7 +79,5 @@ private: std::string mCurrentURL; }; -extern LLViewerHtmlHelp gViewerHtmlHelp; - #endif // LL_LLFLOATERMEDIABROWSER_H diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 4d154c4cd3..3dcdc2f56e 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -1,6 +1,6 @@ /** * @file llfloaterreporter.cpp - * @brief Bug and abuse reports. + * @brief Abuse reports. * * $LicenseInfo:firstyear=2002&license=viewergpl$ * @@ -220,8 +220,7 @@ LLFloaterReporter::~LLFloaterReporter() void LLFloaterReporter::draw() { // this is set by a static callback sometime after the dialog is created. - // Only disable screenshot for abuse reports to estate owners - bug reports always - // allow screenshots to be taken. + // Only disable screenshot for abuse reports to estate owners if ( mEmailToEstateOwner ) { childSetValue("screen_check", FALSE ); @@ -479,15 +478,6 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) if (f) { f->setReportType(report_type); - - if (report_type == BUG_REPORT) - { - LLNotifications::instance().add("HelpReportBug"); - } - else - { - // popup for abuse reports is triggered elsewhere - } } } @@ -528,14 +518,7 @@ bool LLFloaterReporter::validateReport() U8 category = (U8)category_sd.asInteger(); if (category == 0) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseSelectCategory"); - } - else - { - LLNotifications::instance().add("HelpReportBugSelectCategory"); - } + LLNotifications::instance().add("HelpReportAbuseSelectCategory"); return false; } @@ -561,27 +544,13 @@ bool LLFloaterReporter::validateReport() if ( childGetText("summary_edit").empty() ) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseSummaryEmpty"); - } - else - { - LLNotifications::instance().add("HelpReportBugSummaryEmpty"); - } + LLNotifications::instance().add("HelpReportAbuseSummaryEmpty"); return false; }; if ( childGetText("details_edit") == mDefaultSummary ) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseDetailsEmpty"); - } - else - { - LLNotifications::instance().add("HelpReportBugDetailsEmpty"); - } + LLNotifications::instance().add("HelpReportAbuseDetailsEmpty"); return false; }; return true; diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index f363b9531e..7e8f05e3fc 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -1,7 +1,7 @@ /** * @file llfloaterreporter.h * @author Andrew Meadows - * @brief Bug and abuse reports. + * @brief Abuse reports. * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -48,7 +48,7 @@ class LLMeanCollisionData; struct LLResourceData; // these flags are used to label info requests to the server -const U32 BUG_REPORT_REQUEST = 0x01 << 0; +//const U32 BUG_REPORT_REQUEST = 0x01 << 0; // DEPRECATED const U32 COMPLAINT_REPORT_REQUEST = 0x01 << 1; const U32 OBJECT_PAY_REQUEST = 0x01 << 2; @@ -73,7 +73,7 @@ enum EReportType { NULL_REPORT = 0, // don't use this value anywhere UNKNOWN_REPORT = 1, - BUG_REPORT = 2, + //BUG_REPORT = 2, // DEPRECATED COMPLAINT_REPORT = 3, CS_REQUEST_REPORT = 4 }; diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 09a7edaa43..6ec098b92b 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -36,7 +36,6 @@ #include "llmediactrl.h" // viewer includes -#include "llfloaterhtml.h" #include "llfloaterworldmap.h" #include "lluictrlfactory.h" #include "llurldispatcher.h" @@ -898,15 +897,7 @@ void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self ) if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) { - // If we spawn a new LLFloaterHTML, assume we want it to - // follow this LLMediaCtrl's trust for whether or - // not to open secondlife:///app/ links. JC. -// const bool open_links_externally = false; -// LLFloaterHtml::getInstance()->show( -// event_in.mStringPayload, -// "Second Life Browser", -// open_links_externally, -// mTrusted); + llwarns << "Dead, unimplemented path that we used to send to the built-in browser long ago." << llendl; } } } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 809e1852f4..daf0fbd5e0 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -57,6 +57,7 @@ #include "lluiconstants.h" #include "llurlsimstring.h" #include "llviewerbuild.h" +#include "llviewerhelp.h" #include "llviewertexturelist.h" #include "llviewermenu.h" // for handle_preferences() #include "llviewernetwork.h" @@ -69,7 +70,6 @@ #include "llmediactrl.h" #include "llrootview.h" -#include "llfloatermediabrowser.h" #include "llfloatertos.h" #include "lltrans.h" #include "llglheaders.h" @@ -412,8 +412,8 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) if ( KEY_F1 == key ) { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->getTopicFromFocus()); return TRUE; } diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 0ecdec65d6..19bb60b237 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -44,6 +44,7 @@ #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" +#include "llhelp.h" #include "llresmgr.h" #include "llscrollbar.h" @@ -103,7 +104,7 @@ const std::string HELLO_LSL = " llSay(0, \"Touched.\");\n" " }\n" "}\n"; -const std::string HELP_LSL_URL = "http://wiki.secondlife.com/wiki/LSL_Portal"; +const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal"; const std::string DEFAULT_SCRIPT_NAME = "New Script"; // *TODO:Translate? const std::string DEFAULT_SCRIPT_DESC = "(No Description)"; // *TODO:Translate? @@ -264,7 +265,6 @@ struct LLSECKeywordCompare LLScriptEdCore::LLScriptEdCore( const std::string& sample, - const std::string& help_url, const LLHandle& floater_handle, void (*load_callback)(void*), void (*save_callback)(void*, BOOL), @@ -274,7 +274,6 @@ LLScriptEdCore::LLScriptEdCore( : LLPanel(), mSampleText(sample), - mHelpURL(help_url), mEditor( NULL ), mLoadCallback( load_callback ), mSaveCallback( save_callback ), @@ -436,7 +435,7 @@ void LLScriptEdCore::initMenu() menuItem = getChild("Help..."); menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this)); - menuItem = getChild("LSL Wiki Help..."); + menuItem = getChild("Keyword Help..."); menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this)); } @@ -539,9 +538,12 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) mLiveHelpTimer.stop(); } } - else if (immediate) + else { - setHelpPage(LLStringUtil::null); + if (immediate) + { + setHelpPage(LLStringUtil::null); + } } } @@ -557,6 +559,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) if (!history_combo) return; LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); + url_string.setArg("[LSL_STRING]", help_string); addHelpItemToHistory(help_string); @@ -647,69 +650,52 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS return false; } -// static -bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - switch(option) - { - case 0: - LLWeb::loadURL(notification["payload"]["help_url"]); - break; - default: - break; - } - return false; -} - void LLScriptEdCore::onBtnHelp() { - LLSD payload; - payload["help_url"] = mHelpURL; - LLNotifications::instance().add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog); + LLUI::sHelpImpl->showTopic(HELP_LSL_PORTAL_TOPIC); } void LLScriptEdCore::onBtnDynamicHelp() { LLFloater* live_help_floater = mLiveHelpHandle.get(); - if (live_help_floater) - { - live_help_floater->setFocus(TRUE); - updateDynamicHelp(TRUE); + if (!live_help_floater) + { + live_help_floater = new LLFloater(LLSD()); + LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL); + LLFloater* parent = dynamic_cast(getParent()); + parent->addDependentFloater(live_help_floater, TRUE); + live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this); + live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); + live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this); + live_help_floater->childSetAction("back_btn", onClickBack, this); + live_help_floater->childSetAction("fwd_btn", onClickForward, this); + + LLMediaCtrl* browser = live_help_floater->getChild("lsl_guide_html"); + browser->setAlwaysRefresh(TRUE); + + LLComboBox* help_combo = live_help_floater->getChild("history_combo"); + LLKeywordToken *token; + LLKeywords::keyword_iterator_t token_it; + for (token_it = mEditor->keywordsBegin(); + token_it != mEditor->keywordsEnd(); + ++token_it) + { + token = token_it->second; + help_combo->add(wstring_to_utf8str(token->getToken())); + } + help_combo->sortByName(); - return; + // re-initialize help variables + mLastHelpToken = NULL; + mLiveHelpHandle = live_help_floater->getHandle(); + mLiveHelpHistorySize = 0; } - live_help_floater = new LLFloater(LLSD()); - LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL); - LLFloater* parent = dynamic_cast(getParent()); - parent->addDependentFloater(live_help_floater, TRUE); - live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this); - live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); - live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this); - live_help_floater->childSetAction("back_btn", onClickBack, this); - live_help_floater->childSetAction("fwd_btn", onClickForward, this); - - LLMediaCtrl* browser = live_help_floater->getChild("lsl_guide_html"); - browser->setAlwaysRefresh(TRUE); - - LLComboBox* help_combo = live_help_floater->getChild("history_combo"); - LLKeywordToken *token; - LLKeywords::keyword_iterator_t token_it; - for (token_it = mEditor->keywordsBegin(); - token_it != mEditor->keywordsEnd(); - ++token_it) - { - token = token_it->second; - help_combo->add(wstring_to_utf8str(token->getToken())); - } - help_combo->sortByName(); + BOOL visible = TRUE; + BOOL take_focus = TRUE; + live_help_floater->setVisible(visible); + live_help_floater->setFrontmost(take_focus); - // re-initialize help variables - mLastHelpToken = NULL; - mLiveHelpHandle = live_help_floater->getHandle(); - mLiveHelpHistorySize = 0; updateDynamicHelp(TRUE); } @@ -945,7 +931,6 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) self->mScriptEd = new LLScriptEdCore( HELLO_LSL, - HELP_LSL_URL, self->getHandle(), LLPreviewLSL::onLoad, LLPreviewLSL::onSave, @@ -1411,7 +1396,6 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) self->mScriptEd = new LLScriptEdCore( HELLO_LSL, - HELP_LSL_URL, self->getHandle(), &LLLiveLSLEditor::onLoad, &LLLiveLSLEditor::onSave, diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 623886101a..a00f580e32 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -64,7 +64,6 @@ class LLScriptEdCore : public LLPanel public: LLScriptEdCore( const std::string& sample, - const std::string& help_url, const LLHandle& floater_handle, void (*load_callback)(void* userdata), void (*save_callback)(void* userdata, BOOL close_after_save), @@ -86,7 +85,6 @@ public: bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response); - static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); static void onCheckLock(LLUICtrl*, void*); static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata); static void onClickBack(void* userdata); @@ -116,7 +114,6 @@ protected: private: std::string mSampleText; - std::string mHelpURL; LLTextEditor* mEditor; void (*mLoadCallback)(void* userdata); void (*mSaveCallback)(void* userdata, BOOL close_after_save); @@ -124,7 +121,6 @@ private: void* mUserdata; LLComboBox *mFunctions; BOOL mForceClose; - //LLPanel* mGuiPanel; LLPanel* mCodePanel; LLScrollListCtrl* mErrorList; LLDynamicArray mBridges; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6a55b571ae..053b863b6d 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1429,6 +1429,17 @@ bool idle_startup() LLStartUp::deletePasswordFromDisk(); } + // this is the base used to construct help URLs + text = LLUserAuth::getInstance()->getResponse("help_url_format"); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + + // don't fall back to Nebraska's pre-connection static help + gSavedSettings.setBOOL("HelpUseLocal", false); + } + // this is their actual ability to access content text = LLUserAuth::getInstance()->getResponse("agent_access_max"); if (!text.empty()) diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 901d0594f1..e7a8ad6605 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -37,7 +37,7 @@ #include "llagent.h" // teleportViaLocation() #include "llcommandhandler.h" #include "llfloaterdirectory.h" -#include "llfloatermediabrowser.h" +#include "llfloaterhelpbrowser.h" #include "llfloaterreg.h" #include "llfloaterurldisplay.h" #include "llfloaterworldmap.h" @@ -105,7 +105,7 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool trusted_browser) { if (url.empty()) return false; - if (dispatchHelp(url, right_mouse)) return true; + //if (dispatchHelp(url, right_mouse)) return true; if (dispatchApp(url, right_mouse, web, trusted_browser)) return true; if (dispatchRegion(url, right_mouse)) return true; @@ -139,19 +139,6 @@ bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url) return dispatchCore(url, right_click, web, trusted_browser); } -// static -bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse) -{ -#if LL_LIBXUL_ENABLED - if (LLSLURL::isURLHelp(url)) - { - gViewerHtmlHelp.show(); - return true; - } -#endif - return false; -} - // static bool LLURLDispatcherImpl::dispatchApp(const std::string& url, bool right_mouse, diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 51d699c0f7..725ed57d20 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -65,7 +65,7 @@ #include "llfloatergodtools.h" #include "llfloatergroups.h" #include "llfloaterhardwaresettings.h" -#include "llfloaterhtmlcurrency.h" +#include "llfloaterhelpbrowser.h" #include "llfloatermediabrowser.h" #include "llfloaterhud.h" #include "llfloaterimagepreview.h" @@ -164,8 +164,8 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("html_simple", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -244,11 +244,6 @@ void LLViewerFloaterReg::registerFloaters() // debug use only LLFloaterReg::add("media_remote_ctrl", "floater_media_remote.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - - // Untested / dangerous - not for release -#if !LL_RELEASE_FOR_DOWNLOAD - LLFloaterReg::add("buy_currency_html", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); -#endif LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving } diff --git a/indra/newview/llviewerhelp.cpp b/indra/newview/llviewerhelp.cpp new file mode 100644 index 0000000000..0e0727e382 --- /dev/null +++ b/indra/newview/llviewerhelp.cpp @@ -0,0 +1,125 @@ +/** + * @file llviewerhelp.cpp + * @brief Utility functions for the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterhelpbrowser.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llviewercontrol.h" +#include "llversionviewer.h" +#include "llappviewer.h" + +#include "llviewerhelputil.h" +#include "llviewerhelp.h" + + +////////////////////////////// +// implement LLHelp interface + +void LLViewerHelp::showTopic(const std::string &topic) +{ + showHelp(); + + if( gSavedSettings.getBOOL("HelpUseLocal") ) + { + LLFloaterHelpBrowser* helpbrowser = dynamic_cast(LLFloaterReg::getInstance("help_browser")); + helpbrowser->navigateToLocalPage( "help-offline" , "index.html" ); + } + else + { + const LLOSInfo& osinfo = LLAppViewer::instance()->getOSInfo(); + std::string helpURL = LLViewerHelpUtil::buildHelpURL( topic, gSavedSettings, osinfo ); + setRawURL( helpURL ); + } +} + +std::string LLViewerHelp::defaultTopic() +{ + // *hack: to be done properly + return "this_is_fallbacktopic"; +} + +////////////////////////////// +// our own interfaces + +std::string LLViewerHelp::getTopicFromFocus() +{ + // use UI element with viewer's keyboard focus as basis for searching + LLUICtrl* focused = dynamic_cast(gFocusMgr.getKeyboardFocus()); + + if (focused) + { + std::string topic; + if (focused->findHelpTopic(topic)) + { + return topic; + } + } + + // didn't find a help topic in the UI hierarchy for focused + // element, return the fallback topic name instead. + return defaultTopic(); +} + +// static +void LLViewerHelp::showHelp() +{ + LLFloaterHelpBrowser* helpbrowser = dynamic_cast(LLFloaterReg::getInstance("help_browser")); + if (helpbrowser) + { + BOOL visible = TRUE; + BOOL take_focus = TRUE; + helpbrowser->setVisible(visible); + helpbrowser->setFrontmost(take_focus); + } + else + { + llwarns << "Eep, help_browser floater not found" << llendl; + } +} + +// static +void LLViewerHelp::setRawURL(std::string url) +{ + LLFloaterHelpBrowser* helpbrowser = dynamic_cast(LLFloaterReg::getInstance("help_browser")); + if (helpbrowser) + { + helpbrowser->openMedia(url); + } + else + { + llwarns << "Eep, help_browser floater not found" << llendl; + } +} + diff --git a/indra/newview/llviewerhelp.h b/indra/newview/llviewerhelp.h new file mode 100644 index 0000000000..17aab6f239 --- /dev/null +++ b/indra/newview/llviewerhelp.h @@ -0,0 +1,65 @@ +/** + * @file llviewerhelp.h + * @brief Utility functions for the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERHELP_H +#define LL_LLVIEWERHELP_H + +// The Help UI lives in llfloaterhelpbrowser, llviewerhelp provides a +// layer of abstraction that protects help-system-using code from the details of +// the Help UI floater and how help topics are converted into URLs. + +#include "llhelp.h" // our abstract base +#include "llsingleton.h" + +class LLUICtrl; + +class LLViewerHelp : public LLHelp, public LLSingleton +{ + friend class LLSingleton; + + public: + /// display the specified help topic in the help viewer + /*virtual*/ void showTopic(const std::string &topic); + + /// return default (fallback) topic name suitable for showTopic() + /*virtual*/ std::string defaultTopic(); + + // return topic derived from viewer UI focus, else default topic + std::string getTopicFromFocus(); + + private: + static void showHelp(); // make sure help UI is visible & raised + static void setRawURL(std::string url); // send URL to help UI +}; + +#endif // header guard diff --git a/indra/newview/llviewerhelputil.cpp b/indra/newview/llviewerhelputil.cpp new file mode 100644 index 0000000000..c1555eacdc --- /dev/null +++ b/indra/newview/llviewerhelputil.cpp @@ -0,0 +1,114 @@ +/** + * @file llviewerhelp.cpp + * @brief Utility functions for the Help system + * @author Soft Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llversionviewer.h" + +//#include "llfloaterhelpbrowser.h" +//#include "llfloaterreg.h" +//#include "llfocusmgr.h" +//#include "llviewercontrol.h" +//#include "llappviewer.h" + +#include "llstring.h" +#include "lluri.h" +#include "llsys.h" + +#include "llcontrol.h" + +#include "llviewerhelputil.h" + + +////////////////////////////////////////////// +// Build a help URL from a topic and formatter + +//static +std::string LLViewerHelpUtil::helpURLEncode( const std::string &component ) +{ + // Every character rfc3986 allows as unreserved in 2.3, minus the tilde + // which we may grant special meaning. Yay. + const char* allowed = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._"; + std::string escaped = LLURI::escape(component, allowed); + + return escaped; +} + +static std::string buildHelpVersion( const U32 ver_int ) +{ + std::ostringstream ver_str; + ver_str << ver_int; + return ver_str.str(); // not encoded - numbers are rfc3986-safe +} + +//static +std::string LLViewerHelpUtil::buildHelpURL( const std::string &topic, + LLControlGroup &savedSettings, + const LLOSInfo &osinfo ) +{ + std::string helpURL = savedSettings.getString("HelpURLFormat"); + LLSD substitution; + substitution["TOPIC"] = helpURLEncode(topic); + + substitution["CHANNEL"] = helpURLEncode(savedSettings.getString("VersionChannelName")); + + // *TODO: We should put this version pattern in a central place; this and near + // equivalents are replicated in other code - what's a good location? + std::ostringstream version; + version << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + substitution["VERSION"] = helpURLEncode(version.str()); + substitution["VERSION_MAJOR"] = buildHelpVersion(LL_VERSION_MAJOR); + substitution["VERSION_MINOR"] = buildHelpVersion(LL_VERSION_MINOR); + substitution["VERSION_PATCH"] = buildHelpVersion(LL_VERSION_PATCH); + substitution["VERSION_BUILD"] = buildHelpVersion(LL_VERSION_BUILD); + + substitution["OS"] = helpURLEncode(osinfo.getOSStringSimple()); + + std::string language = savedSettings.getString("Language"); + if( language.empty() || language == "default" ) + { + language = savedSettings.getString("SystemLanguage"); + } + substitution["LANGUAGE"] = helpURLEncode(language); + + LLStringUtil::format(helpURL, substitution); + + return helpURL; +} diff --git a/indra/newview/llviewerhelputil.h b/indra/newview/llviewerhelputil.h new file mode 100644 index 0000000000..8ee0d96023 --- /dev/null +++ b/indra/newview/llviewerhelputil.h @@ -0,0 +1,49 @@ +/** + * @file llviewerhelputil.h + * @brief Utility functions for the Help system + * @author Soft Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERHELPUTIL_H +#define LL_LLVIEWERHELPUTIL_H + +class LLControlGroup; +class LLOSInfo; + +class LLViewerHelpUtil +{ + public: + static std::string helpURLEncode( const std::string &component ); + static std::string buildHelpURL( const std::string &topic, + LLControlGroup &savedSettings, + const LLOSInfo &osinfo); +}; + +#endif // header guard diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a0bd5f301b..671a62962b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -103,9 +103,6 @@ #include "llfloatergodtools.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" -#include "llfloaterhtmlcurrency.h" -#include "llfloatermediabrowser.h" // gViewerHtmlHelp -#include "llfloaterhtmlsimple.h" #include "llfloaterhud.h" #include "llfloaterinspect.h" #include "llfloaterlagmeter.h" @@ -182,6 +179,7 @@ #include "lluuid.h" #include "llviewercamera.h" #include "llviewergenericmessage.h" +#include "llviewerhelp.h" #include "llviewertexturelist.h" // gTextureList #include "llviewerinventory.h" #include "llviewermenufile.h" // init_menu_file() @@ -375,7 +373,6 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt void dump_select_mgr(void*); void dump_inventory(void*); -void edit_ui(void*); void toggle_visibility(void*); BOOL get_visibility(void*); @@ -1247,21 +1244,6 @@ class LLAdvancedBuyCurrencyTest : public view_listener_t }; -//////////////////////// -// TOGGLE EDITABLE UI // -//////////////////////// - - -class LLAdvancedToggleEditableUI : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - edit_ui(NULL); - return true; - } -}; - - ///////////////////// // DUMP SELECT MGR // ///////////////////// @@ -5587,11 +5569,6 @@ class LLObjectEnableSitOrStand : public view_listener_t } }; -void edit_ui(void*) -{ - LLFloater::setEditModeEnabled(!LLFloater::getEditModeEnabled()); -} - void dump_select_mgr(void*) { LLSelectMgr::getInstance()->dump(); @@ -5649,8 +5626,8 @@ class LLShowFloater : public view_listener_t } else if (floater_name == "help f1") { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->getTopicFromFocus()); } else if (floater_name == "complaint reporter") { @@ -7886,7 +7863,6 @@ void initialize_menus() // Advanced > UI view_listener_t::addMenu(new LLAdvancedWebBrowserTest(), "Advanced.WebBrowserTest"); view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedToggleEditableUI(), "Advanced.ToggleEditableUI"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); view_listener_t::addMenu(new LLAdvancedDumpFocusHolder(), "Advanced.DumpFocusHolder"); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index c5b09403cb..7ca11d8364 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -50,7 +50,6 @@ #include "llfirstuse.h" #include "llfloaterbuyland.h" #include "llfloatergroups.h" -//#include "llfloaterhtml.h" #include "llfloatersellland.h" #include "llfloatertools.h" #include "llnotify.h" diff --git a/indra/newview/skins/default/html/en-us/help-offline/index.html b/indra/newview/skins/default/html/en-us/help-offline/index.html new file mode 100644 index 0000000000..bf3677603e --- /dev/null +++ b/indra/newview/skins/default/html/en-us/help-offline/index.html @@ -0,0 +1,29 @@ + + + +Offline Help + + + +
+

+ Second Life Offline Help. +

+

+ You are not online and are configured not to fetch help remotely. This is all the help that is available + until more stuff is done. Yeah. +

+
+ + diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 46c294768d..66ea444c15 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -110,12 +110,10 @@ - - @@ -125,16 +123,16 @@ - - - + + + @@ -442,8 +440,6 @@ - - @@ -493,10 +489,6 @@ - - - - diff --git a/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png new file mode 100644 index 0000000000..1e753aaf1d Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png b/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png new file mode 100644 index 0000000000..be66b05230 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png differ diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 97afe6d324..c9e143bf95 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -3,6 +3,7 @@ height="440" layout="topleft" name="floater_about" + help_topic="floater_about" save_rect="true" title="About [APP_NAME]" width="470"> diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml index a1265d49f9..512b4c85a1 100644 --- a/indra/newview/skins/default/xui/en/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml @@ -1,7 +1,7 @@ + title="Help Browser" + width="620"> http://www.secondlife.com @@ -20,150 +20,13 @@ http://support.secondlife.com - - diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 13a53a4ce3..0f7afcba6e 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -93,7 +93,6 @@ Restore Minimize Tear Off - Edit Dock Undock Show Help diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp new file mode 100644 index 0000000000..40f7d532bc --- /dev/null +++ b/indra/newview/tests/llviewerhelputil_test.cpp @@ -0,0 +1,127 @@ +/** + * @file llviewerhelputil_test.cpp + * @brief LLViewerHelpUtil tests + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "../test/lltut.h" + +#include "../llviewerhelputil.h" +#include "llcontrol.h" +#include "llsys.h" + +#include + +//---------------------------------------------------------------------------- +// Implementation of enough of LLControlGroup to support the tests: + +static std::map test_stringvec; + +LLControlGroup::LLControlGroup(const std::string& name) + : LLInstanceTracker(name) +{ +} + +LLControlGroup::~LLControlGroup() +{ +} + +// Implementation of just the LLControlGroup methods we requre +BOOL LLControlGroup::declareString(const std::string& name, + const std::string& initial_val, + const std::string& comment, + BOOL persist) +{ + test_stringvec[name] = initial_val; + return true; +} + +void LLControlGroup::setString(const std::string& name, const std::string& val) +{ + test_stringvec[name] = val; +} + +std::string LLControlGroup::getString(const std::string& name) +{ + return test_stringvec[name]; +} + +//---------------------------------------------------------------------------- + +namespace tut +{ + struct viewerhelputil + { + }; + + typedef test_group viewerhelputil_t; + typedef viewerhelputil_t::object viewerhelputil_object_t; + tut::viewerhelputil_t tut_viewerhelputil("viewerhelputil"); + + template<> template<> + void viewerhelputil_object_t::test<1>() + { + LLOSInfo osinfo; + LLControlGroup cgr("test"); + cgr.declareString("HelpURLFormat", "fooformat", "declared_for_test", FALSE); + cgr.declareString("VersionChannelName", "foochannelname", "declared_for_test", FALSE); + cgr.declareString("Language", "foolanguage", "declared_for_test", FALSE); + std::string topic("test_topic"); + + std::string subresult; + + cgr.setString("HelpURLFormat", "fooformat"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("no substitution tags", subresult, "fooformat"); + + cgr.setString("HelpURLFormat", ""); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("blank substitution format", subresult, ""); + + cgr.setString("HelpURLFormat", "[LANGUAGE]"); + cgr.setString("Language", ""); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("simple substitution with blank", subresult, ""); + + cgr.setString("HelpURLFormat", "[LANGUAGE]"); + cgr.setString("Language", "Esperanto"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("simple substitution", subresult, "Esperanto"); + + cgr.setString("HelpURLFormat", "[XXX]"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("unknown substitution", subresult, "[XXX]"); + + cgr.setString("HelpURLFormat", "[LANGUAGE]/[LANGUAGE]"); + cgr.setString("Language", "Esperanto"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("multiple substitution", subresult, "Esperanto/Esperanto"); + } + +} -- cgit v1.2.3 From a0596b4d5c0c0aa7a9dfb88ad5d28d28a0c86fa9 Mon Sep 17 00:00:00 2001 From: Ramzi Ramey Date: Wed, 30 Sep 2009 18:15:37 +0000 Subject: DEV-40452 VWR-15527: Correct small errors and linguistic consistency in the LSL editor tooltips - also fixes the specific cases of VWR-3766, VWR-1794 - string changes only, NO CODE changed. - this is needed so that we can begin the Localization round --- indra/newview/skins/default/xui/en/strings.xml | 773 ++++++++++++------------- 1 file changed, 386 insertions(+), 387 deletions(-) diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 0f7afcba6e..311bf0503a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -307,112 +307,115 @@ Sleeps script for [SLEEP_TIME] seconds. float llSin(float theta) -theta in radians +Returns the sine of theta (theta in radians) float llCos(float theta) -theta in radians +Returns the cosine of theta (theta in radians) float llTan(float theta) -theta radians +Returns the tangent of theta (theta in radians) float llAtan2(float y, float x) +Returns the arctangent2 of y, x float llSqrt(float val) -returns 0 and triggers a Math Error for imaginary results +Returns the square root of val, or returns 0 and triggers a Math Error for imaginary results float llPow(float base, float exponent) -returns 0 and triggers Math Error for imaginary results +Returns the base raised to the power exponent, or returns 0 and triggers Math Error for imaginary results integer llAbs(integer val) +Returns the positive version of val float llFabs(float val) +Returns the positive version of val float llFrand(float mag) -returns random number in range [0,mag) +Returns a pseudo random number in the range [0,mag) or (mag,0] integer llFloor(float val) -returns largest integer value <= val +Returns largest integer value <= val integer llCeil(float val) -returns smallest integer value >= val +Returns smallest integer value >= val integer llRound(float val) -returns val rounded to the nearest integer +Returns val rounded to the nearest integer float llVecMag(vector v) -returns the magnitude of v +Returns the magnitude of v vector llVecNorm(vector v) -returns the v normalized +Returns the v normalized float llVecDist(vector v1, vector v2) -returns the 3D distance between v1 and v2 +Returns the 3D distance between v1 and v2 vector llRot2Euler(rotation q) -returns the Euler representation (roll, pitch, yaw) of q +Returns the Euler representation (roll, pitch, yaw) of q rotation llEuler2Rot(vector v) -returns the rotation representation of Euler Angles v +Returns the rotation representation of Euler Angles v rotation llAxes2Rot(vector fwd, vector left, vector up) -returns the rotation defined by the coordinate axes +Returns the rotation defined by the coordinate axes vector llRot2Fwd(rotation q) -returns the forward vector defined by q +Returns the forward vector defined by q vector llRot2Left(rotation q) -returns the left vector defined by q +Returns the left vector defined by q vector llRot2Up(rotation q) -returns the up vector defined by q +Returns the up vector defined by q rotation llRotBetween(vector v1, vector v2) -returns the rotation to rotate v1 to v2 +Returns the rotation to rotate v1 to v2 llWhisper(integer channel, string msg) -whispers msg on channel +Whispers the text of msg on channel llSay(integer channel, string msg) -says msg on channel +Says the text of msg on channel llShout(integer channel, string msg) -shouts msg on channel +Shouts the text of msg on channel integer llListen(integer channel, string name, key id, string msg) -sets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen +Sets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen llListenControl(integer number, integer active) -makes a listen event callback active or inactive +Makes a listen event callback active or inactive llListenRemove(integer number) -removes listen event callback number +Removes listen event callback number llSensor(string name, key id, integer type, float range, float arc) @@ -420,43 +423,43 @@ Performs a single scan for name and id with type (AGENT, ACTIVE, PASSIVE, and/or llSensorRepeat(string name, key id, integer type, float range, float arc, float rate) -sets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds +Sets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds llSensorRemove() -removes sensor +Removes the sensor setup by llSensorRepeat string llDetectedName(integer number) -returns the name of detected object number (returns empty string if number is not valid sensed object) +Returns the name of detected object number (returns empty string if number is not a valid sensed object) key llDetectedKey(integer number) -returns the key of detected object number (returns empty key if number is not valid sensed object) +Returns the key of detected object number (returns empty key if number is not a valid sensed object) key llDetectedOwner(integer number) -returns the key of detected object's owner (returns empty key if number is not valid sensed object) +Returns the key of detected object's owner (returns empty key if number is not a valid sensed object) integer llDetectedType(integer number) -returns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not valid sensed object) +Returns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not a valid sensed object) vector llDetectedPos(integer number) -returns the position of detected object number (returns <0,0,0> if number is not valid sensed object) +Returns the position of detected object number (returns <0,0,0> if number is not a valid sensed object) vector llDetectedVel(integer number) -returns the velocity of detected object number (returns <0,0,0> if number is not valid sensed object) +Returns the velocity of detected object number (returns <0,0,0> if number is not a valid sensed object) vector llDetectedGrab(integer number) -returns the grab offset of the user touching object (returns <0,0,0> if number is not valid sensed object) +Returns the grab offset of the user touching object (returns <0,0,0> if number is not a valid sensed object) rotation llDetectedRot(integer number) -returns the rotation of detected object number (returns <0,0,0,1> if number is not valid sensed object) +Returns the rotation of detected object number (returns <0,0,0,1> if number is not a valid sensed object) integer llDetectedGroup(integer number) @@ -464,127 +467,127 @@ Returns TRUE if detected object is part of same group as owner integer llDetectedLinkNumber(integer number) -returns the link position of the triggered event for touches and collisions only +Returns the link position of the triggered event for touches and collisions only llDie() -deletes the object +Deletes the object -float llGround(vector v) -returns the ground height below the object position + v +float llGround(vector offset) +Returns the ground height below the object position + offset -float llCloud(vector v) -returns the cloud density at the object position + v +float llCloud(vector offset) +Returns the cloud density at the object position + offset -vector llWind(vector v) -returns the wind velocity at the object position + v +vector llWind(vector offset) +Returns the wind velocity at the object position + offset llSetStatus(integer status, integer value) -sets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value +Sets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value integer llGetStatus(integer status) -gets value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) +Returns value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) llSetScale(vector scale) -sets the scale +Sets the scale of the prim vector llGetScale() -gets the scale +Returns the scale of the prim llSetColor(vector color, integer face) -sets the color +Sets the color on face of the prim float llGetAlpha(integer face) -gets the alpha +Returns the alpha of face llSetAlpha(float alpha, integer face) -sets the alpha +Sets the alpha on face vector llGetColor(integer face) -gets the color +Returns the color on face llSetTexture(string texture, integer face) -sets the texture of face +Sets the texture of face or ALL_SIDES -llScaleTexture(float scales, float scalet, integer face) -sets the texture s, t scales for the chosen face +llScaleTexture(float u, float v, integer face) +Sets the texture u & v scales for the chosen face or ALL_SIDES -llOffsetTexture(float offsets, float offsett, integer face) -sets the texture s, t offsets for the chosen face +llOffsetTexture(float u, float v, integer face) +Sets the texture u & v offsets for the chosen face or ALL_SIDES llRotateTexture(float rotation, integer face) -sets the texture rotation for the chosen face +Sets the texture rotation for the chosen face string llGetTexture(integer face) -gets the texture of face (if it's a texture in the object inventory, otherwise the key in a string) +Returns a string that is the texture on face (the inventory name if it is a texture in the prim's inventory, otherwise the key) llSetPos(vector pos) -sets the position (if the script isn't physical) +Moves the object or prim towards pos without using physics (if the script isn't physical) vector llGetPos() -gets the position (if the script isn't physical) +Returns the position of the task in region coordinates vector llGetLocalPos() -gets the position relative to the root (if the script isn't physical) +Returns the position relative to the root llSetRot(rotation rot) -sets the rotation (if the script isn't physical) +Sets the rotation rotation llGetRot() -gets the rotation (if the script isn't physical) +Returns the rotation relative to the region's axes rotation llGetLocalRot() -gets the rotation local to the root (if the script isn't physical) +Returns the rotation local to the root llSetForce(vector force, integer local) -sets force on object, in local coords if local == TRUE (if the script is physical) +Applies force to the object (if the script is physical), in local coords if local == TRUE vector llGetForce() -gets the force (if the script is physical) +Returns the force (if the script is physical) integer llTarget(vector position, float range) -set positions within range of position as a target and return an ID for the target +Sets positions within range of position as a target and return an ID for the target llTargetRemove(integer number) -removes target number +Removes positional target number registered with llTarget integer llRotTarget(rotation rot, float error) -set rotations with error of rot as a rotational target and return an ID for the rotational target +Set rotations with error of rot as a rotational target and return an ID for the rotational target llRotTargetRemove(integer number) -removes rotational target number +Removes rotational target number registered with llRotTarget llMoveToTarget(vector target, float tau) -critically damp to target in tau seconds (if the script is physical) +Critically damps to target in tau seconds (if the script is physical) llStopMoveToTarget() @@ -592,83 +595,83 @@ Stops critically damped motion llApplyImpulse(vector force, integer local) -applies impulse to object, in local coords if local == TRUE (if the script is physical) +Applies impulse to object (if the script is physical), in local coords if local == TRUE llApplyRotationalImpulse(vector force, integer local) -applies rotational impulse to object, in local coords if local == TRUE (if the script is physical) +Applies rotational impulse to object (if the script is physical), in local coords if local == TRUE llSetTorque(vector torque, integer local) -sets the torque of object, in local coords if local == TRUE (if the script is physical) +Sets the torque of object (if the script is physical), in local coords if local == TRUE vector llGetTorque() -gets the torque (if the script is physical) +Returns the torque (if the script is physical) llSetForceAndTorque(vector force, vector torque, integer local) -sets the force and torque of object, in local coords if local == TRUE (if the script is physical) +Sets the force and torque of object (if the script is physical), in local coords if local == TRUE vector llGetVel() -gets the velocity +Returns the velocity of the object vector llGetAccel() -gets the acceleration +Returns the acceleration of the object relative to the region's axes vector llGetOmega() -gets the omega +Returns the rotation velocity in radians per second float llGetTimeOfDay() -gets the time in seconds since [SECOND_LIFE] server midnight (or since server up-time; whichever is smaller) +Returns the time in seconds since [SECOND_LIFE] server midnight or since region up-time, whichever is smaller float llGetWallclock() -gets the time in seconds since midnight +Returns the time in seconds since midnight California Pacific time (PST/PDT) float llGetTime() -gets the time in seconds since creation +Returns the time in seconds since the last region reset, script reset, or call to either llResetTime or llGetAndResetTime llResetTime() -sets the time to zero +Sets the script timer to zero float llGetAndResetTime() -gets the time in seconds since creation and sets the time to zero +Returns the script time in seconds and then resets the script timer to zero llSound(string sound, float volume, integer queue, integer loop) -plays sound at volume and whether it should loop or not +Plays sound at volume and whether it should loop or not llPlaySound(string sound, float volume) -plays attached sound once at volume (0.0 - 1.0) +Plays attached sound once at volume (0.0 - 1.0) llLoopSound(string sound, float volume) -plays attached sound looping indefinitely at volume (0.0 - 1.0) +Plays attached sound looping indefinitely at volume (0.0 - 1.0) llLoopSoundMaster(string sound, float volume) -plays attached sound looping at volume (0.0 - 1.0), declares it a sync master +Plays attached sound looping at volume (0.0 - 1.0), declares it a sync master llLoopSoundSlave(string sound, float volume) -plays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master +Plays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master llPlaySoundSlave(string sound, float volume) -plays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master +Plays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master llTriggerSound(string sound, float volume) -plays sound at volume (0.0 - 1.0), centered at but not attached to object +Plays sound at volume (0.0 - 1.0), centered at but not attached to object llStopSound() @@ -676,143 +679,143 @@ Stops currently attached sound llPreloadSound(string sound) -preloads a sound on viewers within range +Preloads a sound on viewers within range string llGetSubString(string src, integer start, integer end) -returns the indicated substring +Returns the indicated substring string llDeleteSubString(string src, integer start, integer end) -removes the indicated substring and returns the result +Removes the indicated substring and returns the result string llInsertString(string dst, integer position, string src) -inserts src into dst at position and returns the result +Returns a destination string dst with the string src inserted starting at position pos string llToUpper(string src) -convert src to all upper case and returns the result +Returns a string that is src with all upper-case characters string llToLower(string src) -convert src to all lower case and returns the result +Returns a string that is src with all lower-case characters llGiveMoney(key destination, integer amount) -transfer amount of money from script owner to destination +Transfers amount of L$ from script owner to destination llMakeExplosion(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make a round explosion of particles +Makes a round explosion of particles llMakeFountain(integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset) -Make a fountain of particles +Makes a fountain of particles llMakeSmoke(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make smoke like particles +Makes smoke like particles llMakeFire(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make fire like particles +Makes fire like particles llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param) -Instanciate owners inventory object at pos with velocity vel and rotation rot with start parameter param +Instantiates owner's inventory object at pos with velocity vel and rotation rot with start parameter param -llLookAt(vector target, F32 strength, F32 damping) -Cause object name to point it's forward axis towards target +llLookAt(vector target, float strength, float damping) +Causes object to point its up axis (positive z) towards target, while keeping its forward axis (positive x) below the horizon llStopLookAt() -Stop causing object name to point at a target +Stops causing object to point at a target llSetTimerEvent(float sec) -Cause the timer event to be triggered every sec seconds +Causes the timer event to be triggered a maximum of once every sec seconds llSleep(float sec) -Put script to sleep for sec seconds +Puts the script to sleep for sec seconds float llGetMass() -Get the mass of task name that script is attached to +Returns the mass of object that the script is attached to llCollisionFilter(string name, key id, integer accept) -if accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id +Sets the collision filter, exclusively or inclusively. If accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id llTakeControls(integer controls, integer accept, integer pass_on) -Take controls from agent task has permissions for. If (accept == (controls & input)), send input to task. If pass_on send to agent also. +Allows for intercepting keyboard and mouse clicks from the agent the script has permissions for llReleaseControls() -Stop taking inputs +Stops taking inputs that were taken with llTakeControls -llAttachToAvatar(integer attachment) -Attach to avatar task has permissions for at point attachment +llAttachToAvatar(integer attach_point) +Attaches the object to the avatar who has granted permission to the script llDetachFromAvatar() -Drop off of avatar +Detaches object from avatar llTakeCamera(key avatar) -Move avatar's viewpoint to task +Moves avatar's viewpoint to task llReleaseCamera(key avatar) -Return camera to agent +Returns camera to agent avatar key llGetOwner() -Returns the owner of the task +Returns the object owner's UUID llInstantMessage(key user, string message) -IMs message to the user +Sends the specified string as an Instant Message to the user llEmail(string address, string subject, string message) -Sends email to address with subject and message +Sends an email to address with the subject and message llGetNextEmail(string address, string subject) -Get the next waiting email with appropriate address and/or subject (if blank they are ignored) +Gets the next waiting email that comes from address, with specified subject key llGetKey() -Get the key for the task the script is attached to +Returns the key of the prim the script is attached to llSetBuoyancy(float buoyancy) -Set the tasks buoyancy (0 is none, < 1.0 sinks, 1.0 floats, > 1.0 rises) +Sets the buoyancy of the task or object (0 is disabled, < 1.0 sinks, 1.0 floats, > 1.0 rises) llSetHoverHeight(float height, integer water, float tau) -Critically damps to a height (either above ground level or above the higher of land and water if water == TRUE) +Critically damps to a height above the ground (or water) in tau seconds llStopHover() -Stop hovering to a height +Stops hovering to a height llMinEventDelay(float delay) -Set the minimum time between events being handled +Sets the minimum time between events being handled llSoundPreload(string sound) -preloads a sound on viewers within range +Preloads a sound on viewers within range -llRotLookAt(rotation target, F32 strength, F32 damping) -Cause object name to point it's forward axis towards target +llRotLookAt(rotation target, float strength, float damping) +Causes object name to point its forward axis towards target integer llStringLength(string str) @@ -820,84 +823,83 @@ Returns the length of string llStartAnimation(string anim) -Start animation anim for agent that owns object +Starts animation anim for agent that granted PERMISSION_TRIGGER_ANIMATION if the permission has not been revoked llStopAnimation(string anim) -Stop animation anim for agent that owns object +Stops animation anim for agent that granted permission llPointAt(vector pos) -Make agent that owns object point at pos +Makes agent that owns object point at pos llStopPointAt() -Stop agent that owns object pointing +Stops pointing agent that owns object llTargetOmega(vector axis, float spinrate, float gain) -Attempt to spin at spinrate with strength gain +Rotates the object around axis at spinrate with strength gain integer llGetStartParameter() -Get's the start paramter passed to llRezObject +Returns an integer that is the script start/rez parameter llGodLikeRezObject(key inventory, vector pos) -rez directly off of a UUID if owner has dog-bit set +Rezzes directly off of UUID if owner is in God Mode llRequestPermissions(key agent, integer perm) -ask agent to allow the script to do perm (NB: Debit, ownership, link, joint, and permission requests can only go to the task's owner) +Asks the agent for permission to run certain classes of functions key llGetPermissionsKey() -Return agent that permissions are enabled for. NULL_KEY if not enabled +Returns the key of the avatar that last granted permissions to the script integer llGetPermissions() -return what permissions have been enabled +Returns an integer bitfield with the permissions that have been granted integer llGetLinkNumber() -Returns what number in a link set the script is attached to (0 means no link, 1 the root, 2 for first child, etc) +Returns the link number of the prim containing the script (0 means not linked, 1 the prim is the root, 2 the prim is the first child, etc) llSetLinkColor(integer linknumber, vector color, integer face) -If a task exists in the link chain at linknumber, set face to color +Sets face to color if a task exists in the link chain at linknumber llCreateLink(key target, integer parent) -Attempt to link task script is attached to and target (requires permission PERMISSION_CHANGE_LINKS be set). If parent == TRUE, task script is attached to is the root +Attempts to link the script's object with the target (requires that PERMISSION_CHANGE_LINKS be granted). If parent == TRUE, then the script's object becomes the root llBreakLink(integer linknum) -Delinks the task with the given link number (requires permission PERMISSION_CHANGE_LINKS be set) +Delinks the prim with the given link number in a linked object set (requires that PERMISSION_CHANGE_LINKS be granted) llBreakAllLinks() -Delinks all tasks in the link set (requires permission PERMISSION_CHANGE_LINKS be set) +Delinks all prims in the link set (requires that PERMISSION_CHANGE_LINKS be granted) -key llGetLinkKey(integer linknum) -Get the key of linknumber in link set +key llGetLinkKey(integer linknumber) +Returns the key of the linked prim linknumber -string llGetLinkName(integer linknum) -Get the name of linknumber in link set +string llGetLinkName(integer linknumber) +Returns the name of linknumber in a link set integer llGetInventoryNumber(integer type) -Get the number of items of a given type in the task's inventory. -Valid types: INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_OBJECT, INVENTORY_SCRIPT, INVENTORY_CLOTHING, INVENTORY_BODYPART, INVENTORY_NOTECARD, INVENTORY_LANDMARK, INVENTORY_ALL +Returns the number of items of a given type (INVENTORY_* flag) in the prim's inventory string llGetInventoryName(integer type, integer number) -Get the name of the inventory item number of type +Returns the name of the inventory item number of a given type llSetScriptState(string name, integer run) -Control the state of a script name. +Sets the running state of the specified script float llGetEnergy() @@ -905,56 +907,55 @@ Returns how much energy is in the object as a percentage of maximum llGiveInventory(key destination, string inventory) -Give inventory to destination +Gives inventory to destination -llRemoveInventory(string inventory) -Remove the named inventory item +llRemoveInventory(string item) +Removes the named inventory item llSetText(string text, vector color, float alpha) -Set text floating over object +Displays text that hovers over the prim with specific color and translucency specified with alpha -float llWater(vector v) -returns the water height below the object position + v +float llWater(vector offset) +Returns the water height below the object position + offset llPassTouches(integer pass) -if pass == TRUE, touches are passed from children on to parents (default is FALSE) +If pass == TRUE, touches are passed from children on to parents key llRequestAgentData(key id, integer data) -Requests data about agent id. When data is available the dataserver event will be raised +Requests data about agent id. When data is available the dataserver event will be raised. key llRequestInventoryData(string name) -Requests data from object's inventory object. When data is available the dataserver event will be raised +Requests data from object's inventory object. When data is available the dataserver event will be raised. llSetDamage(float damage) -Sets the amount of damage that will be done to an object that this task hits. Task will be killed. +Sets the amount of damage that will be done when this object hits an avatar. llTeleportAgentHome(key id) -Teleports agent on owner's land to agent's home location +Teleports avatar on the owner's land to their home location without any warning -llModifyLand(integer action, integer size) -Modify land with action (LAND_LEVEL, LAND_RAISE, LAND_LOWER, LAND_SMOOTH, LAND_NOISE, LAND_REVERT) -on size (LAND_SMALL_BRUSH, LAND_MEDIUM_BRUSH, LAND_LARGE_BRUSH) +llModifyLand(integer action, integer brush) +Modifies land using the specified action on the specified brush size of land llCollisionSound(string impact_sound, float impact_volume) -Suppress default collision sounds, replace default impact sounds with impact_sound (empty string to just suppress) +Suppresses default collision sounds, replaces default impact sounds with impact_sound at the volume impact_volume llCollisionSprite(string impact_sprite) -Suppress default collision sprites, replace default impact sprite with impact_sprite (empty string to just suppress) +Suppresses default collision sprites, replaces default impact sprite with impact_sprite (use an empty string to just suppress) string llGetAnimation(key id) -Get the currently playing locomotion animation for avatar id +Returns the name of the currently playing locomotion animation for avatar id llResetScript() @@ -962,12 +963,7 @@ Resets the script llMessageLinked(integer linknum, integer num, string str, key id) -Sends num, str, and id to members of the link set -(LINK_ROOT sends to root task in a linked set, -LINK_SET sends to all tasks, -LINK_ALL_OTHERS to all other tasks, -LINK_ALL_CHILDREN to all children, -LINK_THIS to the task the script it is in) +Allows scripts in the same object to communicate. Triggers a link_message event with the same parameters num, str, and id in all scripts in the prim(s) described by linknum. llPushObject(key id, vector impulse, vector ang_impulse, integer local) @@ -975,19 +971,19 @@ Applies impulse and ang_impulse to object id llPassCollisions(integer pass) -if pass == TRUE, collisions are passed from children on to parents (default is FALSE) +If pass == TRUE, collisions are passed from children on to parents (default is FALSE) -llGetScriptName() -Returns the script name +string llGetScriptName() +Returns the name of the script that this function is used in integer llGetNumberOfSides() -Returns the number of sides +Returns the number of faces (or sides) of the prim rotation llAxisAngle2Rot(vector axis, float angle) -Returns the rotation generated angle about axis +Returns the rotation that is a generated angle about axis vector llRot2Axis(rotation rot) @@ -1011,19 +1007,19 @@ Returns angle between rotation a and b key llGetInventoryKey(string name) -Returns the key of the inventory name +Returns the key that is the UUID of the inventory name llAllowInventoryDrop(integer add) -If add == TRUE, users without permissions can still drop inventory items onto task +If add == TRUE, users without modify permissions can still drop inventory items onto a prim vector llGetSunDirection() -Returns the sun direction on the simulator +Returns a normalized vector of the direction of the sun in the region -vector llGetTextureOffset(integer side) -Returns the texture offset of side in the x and y components of a vector +vector llGetTextureOffset(integer face) +Returns the texture offset of face in the x and y components of a vector vector llGetTextureScale(integer side) @@ -1035,55 +1031,57 @@ Returns the texture rotation of side integer llSubStringIndex(string source, string pattern) -Finds index in source where pattern first appears (returns -1 if not found) +Returns an integer that is the index in source where pattern first appears. +(Returns -1 if not found) key llGetOwnerKey(key id) -Find the owner of id +Returns the owner of object id vector llGetCenterOfMass() -Get the object's center of mass +Returns the prim's center of mass (unless called from the root prim, where it returns the object's center of mass) list llListSort(list src, integer stride, integer ascending) -Sort the list into blocks of stride in ascending order if ascending == TRUE. Note that sort only works between same types. +Sorts the list into blocks of stride, in ascending order if ascending == TRUE. +The sort order is affected by type. integer llGetListLength(list src) -Get the number of elements in the list +Returns the number of elements in the list integer llList2Integer(list src, integer index) -Copy the integer at index in the list +Copies the integer at index in the list float llList2Float(list src, integer index) -Copy the float at index in the list +Copies the float at index in the list string llList2String(list src, integer index) -Copy the string at index in the list +Copies the string at index in the list key llList2Key(list src, integer index) -Copy the key at index in the list +Copies the key at index in the list vector llList2Vector(list src, integer index) -Copy the vector at index in the list +Copies the vector at index in the list rotation llList2Rot(list src, integer index) -Copy the rotation at index in the list +Copies the rotation at index in the list list llList2List(list src, integer start, integer end) -Copy the slice of the list from start to end +Copies the slice of the list from start to end list llDeleteSubList(list src, integer start, integer end) -Remove the slice from the list and return the remainder +Removes the slice from start to end and returns the remainder of the list integer llGetListEntryType(list src, integer index) @@ -1092,11 +1090,11 @@ Returns the type of the index entry in the list string llList2CSV(list src) -Create a string of comma separated values from list +Creates a string of comma separated values from list list llCSV2List(string src) -Create a list from a string of comma separated values +Creates a list from a string of comma separated values list llListRandomize(list src, integer stride) @@ -1104,80 +1102,83 @@ Returns a randomized list of blocks of size stride list llList2ListStrided(list src, integer start, integer end, integer stride) -Copy the strided slice of the list from start to end +Copies the strided slice of the list from start to end vector llGetRegionCorner() -Returns a vector with the south west corner x,y position of the region the object is in +Returns a vector in meters that is the global location of the south-west corner of the region which the object is in list llListInsertList(list dest, list src, integer start) -Inserts src into dest at position start +Returns a list that contains all the elements from dest but with the elements from src inserted at position start integer llListFindList(list src, list test) -Returns the start of the first instance of test in src, -1 if not found +Returns the index of the first instance of test in src. +(Returns -1 if not found) string llGetObjectName() -Returns the name of the object script is attached to +Returns the name of the prim which the script is attached to llSetObjectName(string name) -Sets the objects name +Sets the prim's name to the name parameter string llGetDate() -Gets the date as YYYY-MM-DD +Returns the current date in the UTC time zone in the format YYYY-MM-DD integer llEdgeOfWorld(vector pos, vector dir) -Checks to see whether the border hit by dir from pos is the edge of the world (has no neighboring simulator) +Checks to see whether the border hit by dir from pos is the edge of the world (has no neighboring region) integer llGetAgentInfo(key id) -Gets information about agent ID. -Returns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING, AGENT_IN_AIR and/or AGENT_AUTOPILOT. +Returns an integer bitfield containing the agent information about id. +Returns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING and/or AGENT_IN_AIR. llAdjustSoundVolume(float volume) -adjusts volume of attached sound (0.0 - 1.0) +Adjusts volume of attached sound (0.0 - 1.0) llSetSoundQueueing(integer queue) -determines whether attached sound calls wait for the current sound to finish (0 = no [default], nonzero = yes) +Sets whether attached sounds wait for the current sound to finish (If queue == TRUE then queuing is enabled, if FALSE queuing is disabled [default]) llSetSoundRadius(float radius) -establishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered) +Establishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered) string llKey2Name(key id) -Returns the name of the object key, iff the object is in the current simulator, otherwise the empty string +Returns the name of the prim or avatar specified by id. +(The id must be a valid rezzed prim or avatar key in the current simulator, otherwise an empty string is returned.) llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate) -Animate the texture on the specified face/faces +Animates the texture on the specified face/faces -llTriggerSoundLimited(string sound, float volume, vector tne, vector bsw) -plays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to AABB defined by vectors top-north-east and bottom-south-west +llTriggerSoundLimited(string sound, float volume, vector top_north_east, vector bottom_south_west) +Plays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to the box defined by vectors top_north_east and bottom_south_west -llEjectFromLand(key pest) -Ejects pest from land that you own +llEjectFromLand(key avatar) +Ejects avatar from the parcel list llParseString2List(string src, list separators, list spacers) -Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each) +Breaks src into a list, discarding separators, keeping spacers +(separators and spacers must be lists of strings, maximum of 8 each) integer llOverMyLand(key id) -Returns TRUE if id is over land owner of object owns, FALSE otherwise +Returns TRUE if id is over land owned by the script owner, otherwise FALSE key llGetLandOwnerAt(vector pos) -Returns the key of the land owner, NULL_KEY if public +Returns the key of the land owner, returns NULL_KEY if public key llGetNotecardLine(string name, integer line) @@ -1185,131 +1186,130 @@ Returns line line of notecard name via the dataserver event vector llGetAgentSize(key id) -If the agent is in the same sim as the object, returns the size of the avatar +If the avatar is in the same region, returns the size of the bounding box of the requested avatar by id, otherwise returns ZERO_VECTOR integer llSameGroup(key id) -Returns TRUE if ID is in the same sim and has the same active group, otherwise FALSE +Returns TRUE if avatar id is in the same region and has the same active group, otherwise FALSE key llUnSit(key id) -If agent identified by id is sitting on the object the script is attached to or is over land owned by the objects owner, the agent is forced to stand up +If avatar identified by id is sitting on the object the script is attached to or is over land owned by the object's owner, the avatar is forced to stand up -vector llGroundSlope(vector v) -returns the ground slope below the object position + v +vector llGroundSlope(vector offset) +Returns the ground slope below the object position + offset -vector llGroundNormal(vector v) -returns the ground normal below the object position + v +vector llGroundNormal(vector offset) +Returns the ground normal below the object position + offset -vector llGroundCountour(vector v) -returns the ground contour below the object position + v +vector llGroundCountour(vector offset) +Returns the ground contour direction below the object position + offset integer llGetAttached() -returns the object attachment point or 0 if not attached +Returns the object's attachment point, or 0 if not attached integer llGetFreeMemory() -returns the available heap space for the current script +Returns the number of free bytes of memory the script can use string llGetRegionName() -returns the current region name +Returns the current region name float llGetRegionTimeDilation() -returns the current time dilation as a float between 0 and 1 +Returns the current time dilation as a float between 0.0 (full dilation) and 1.0 (no dilation) float llGetRegionFPS() -returns the mean region frames per second +Returns the mean region frames per second llParticleSystem(list rules) -Creates a particle system based on rules. Empty list removes particle system from object. +Creates a particle system based on rules. An empty list removes the particle system. List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] llGroundRepel(float height, integer water, float tau) -Critically damps to height if within height*0.5 of level (either above ground level or above the higher of land and water if water == TRUE) +Critically damps to height if within height*0.5 of level (either above ground level, or above the higher of land and water if water == TRUE) -llGiveInventoryList(key destination, string category, list inventory) -Give inventory to destination in a new category +llGiveInventoryList(key target, string folder, list inventory) +Gives inventory items to target, creating a new folder to put them in llSetVehicleType(integer type) -sets vehicle to one of the default types +Sets the vehicle to one of the default types llSetVehicleFloatParam(integer param, float value) -sets the specified vehicle float parameter +Sets the specified vehicle float parameter llSetVehicleVectorParam(integer param, vector vec) -sets the specified vehicle vector parameter +Sets the specified vehicle vector parameter llSetVehicleVectorParam(integer param, rotation rot) -sets the specified vehicle rotation parameter +Sets the specified vehicle rotation parameter llSetVehicleFlags(integer flags) -sets the enabled bits in 'flags' +Sets the enabled bits in 'flags' llRemoveVehicleFlags(integer flags) -removes the enabled bits in 'flags' +Removes the enabled bits in 'flags' llSitTarget(vector offset, rotation rot) -Set the sit location for this object (if offset == <0,0,0> clear it) +Sets the sit location for the prim. If offset == <0,0,0> then the sit target is removed. key llAvatarOnSitTarget() -If an avatar is sitting on the sit target, return the avatar's key, NULL_KEY otherwise +If an avatar is seated on the sit target, returns the avatar's key, otherwise NULL_KEY llAddToLandPassList(key avatar, float hours) -Add avatar to the land pass list for hours +Adds avatar to the land pass list for hours, or indefinitely if hours is 0 llSetTouchText(string text) -Displays text in pie menu that acts as a touch +Displays text rather than the default 'Touch' in the pie menu llSetSitText(string text) -Displays text rather than sit in pie menu +Displays text rather than the default 'Sit Here' in the pie menu llSetCameraEyeOffset(vector offset) -Sets the camera eye offset used in this object if an avatar sits on it +Sets the camera eye offset for avatars that sit on the object llSetCameraAtOffset(vector offset) -Sets the camera at offset used in this object if an avatar sits on it +Sets the point the camera is looking at to offset for avatars that sit on the object string llDumpList2String(list src, string separator) -Write the list out in a single string using separator between values +Returns the list in a single string, using separator between the entries integer llScriptDanger(vector pos) -Returns true if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts +Returns TRUE if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts llDialog(key avatar, string message, list buttons, integer chat_channel -Shows a dialog box on the avatar's screen with the message. -Up to 12 strings in the list form buttons. -If a button is clicked, the name is chatted on chat_channel. +Shows a dialog box on the avatar's screen with a message and up to 12 buttons. +If a button is pressed, the avatar says the text of the button label on chat_channel. llVolumeDetect(integer detect) -If detect = TRUE, object becomes phantom but triggers collision_start and collision_end events when other objects start and stop interpenetrating. -Must be applied to the root object. +If detect = TRUE, object works much like Phantom, but triggers collision_start and collision_end events when other objects start and stop interpenetrating. +Must be applied to the root prim. llResetOtherScript(string name) @@ -1317,110 +1317,107 @@ Resets script name integer llGetScriptState(string name) -Resets TRUE if script name is running +Returns TRUE if the script name is running -Deprecated. Please use llRemoteLoadScriptPin instead. +DEPRECATED! Please use llRemoteLoadScriptPin instead. llSetRemoteScriptAccessPin(integer pin) -If pin is set to a non-zero number, the task will accept remote script loads via llRemoteLoadScriptPin if it passes in the correct pin. -Othersise, llRemoteLoadScriptPin is ignored. +If pin is set to a non-zero number, allows a prim to have scripts remotely loaded via llRemoteLoadScriptPin when it passes in the correct pin. Otherwise, llRemoteLoadScriptPin is ignored. llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param) -If the owner of the object this script is attached can modify target, -they are in the same region, and the matching pin is used, -copy script name onto target, -if running == TRUE, start the script with param. +Copies script name onto target, if the owner of this scripted object can modify target and is in the same region, and the matching pin is used. +If running == TRUE, starts the script with start_param llOpenRemoteDataChannel() -Creates a channel to listen for XML-RPC calls. Will trigger a remote_data event with channel id once it is available. +Creates a channel to listen for XML-RPC calls, and will trigger a remote_data event with channel id once it is available key llSendRemoteData(key channel, string dest, integer idata, string sdata) -Send an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata. -A message identifier key is returned. -An XML-RPC reply will trigger a remote_data event and reference the message id. -The message_id is returned. +Sends an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata. +Returns a key that is the message_id for the resulting remote_data events. llRemoteDataReply(key channel, key message_id, string sdata, integer idata) -Send an XML-RPC reply to message_id on channel with payload of string sdata and integer idata +Sends an XML-RPC reply to message_id on channel with payload of string sdata and integer idata llCloseRemoteDataChannel(key channel) -Closes XML-RPC channel. +Closes XML-RPC channel string llMD5String(string src, integer nonce) -Performs a RSA Data Security, Inc. MD5 Message-Digest Algorithm on string with nonce. Returns a 32 character hex string. +Returns a string of 32 hex characters that is a RSA Data Security, Inc. MD5 Message-Digest Algorithm of src with nonce llSetPrimitiveParams(list rules) -Set primitive parameters based on rules. +Sets the prim's parameters according to rules string llStringToBase64(string str) -Converts a string to the Base 64 representation of the string. +Converts a string to the Base64 representation of the string string llBase64ToString(string str) -Converts a Base 64 string to a conventional string. If the conversion creates any unprintable characters, they are converted to spaces. +Converts a Base64 string to a conventional string. +If the conversion creates any unprintable characters, they are converted to spaces. string llXorBase64Strings(string s1, string s2) -DEPRECATED! Please use llXorBase64StringsCorrect instead!! Incorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability. +DEPRECATED! Please use llXorBase64StringsCorrect instead. +Incorrectly performs an exclusive or on two Base64 strings and returns a Base64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability. llRemoteDataSetRegion() -If an object using remote data channels changes regions, you must call this function to reregister the remote data channels. -You do not need to make this call if you don't change regions. +DEPRECATED! Please use llOpenRemoteDataChannel instead. +If an object using remote data channels changes regions, you must call this function to reregister the remote data channels. This call is not needed if the prim does not change regions. float llLog10(float val) -Returns the base 10 log of val if val > 0, otherwise returns 0. +Returns the base 10 logarithm of val. Returns zero if val <= 0. float llLog(float val) -Returns the base e log of val if val > 0, otherwise returns 0. +Returns the natural logarithm of val. Returns zero if val <= 0. list llGetAnimationList(key id) -Gets a list of all playing animations for avatar id +Returns a list of keys of playing animations for avatar described by id llSetParcelMusicURL(string url) -Sets the streaming audio URL for the parcel object is on +Sets the streaming audio URL for the parcel which the object is on vector llGetRootPosition() -Gets the global position of the root object of the object script is attached to +Returns the position (in region coordinates) of the root prim of the object which the script is attached to rotation llGetRootRotation() -Gets the global rotation of the root object of the object script is attached to +Returns the rotation (relative to the region) of the root prim of the object which the script is attached to string llGetObjectDesc() -Returns the description of the object the script is attached to +Returns the description of the prim the script is attached to llSetObjectDesc(string name) -Sets the object's description +Sets the prim's description key llGetCreator() -Returns the creator of the object +Returns a key for the creator of the prim string llGetTimestamp() -Gets the timestamp in the format: YYYY-MM-DDThh:mm:ss.ff..fZ +Returns the timestamp in the UTC time zone in the format: YYYY-MM-DDThh:mm:ss.ff..fZ llSetLinkAlpha(integer linknumber, float alpha, integer face) -If a prim exists in the link chain at linknumber, set face to alpha +If a prim exists in the link chain at linknumber, sets face to alpha integer llGetNumberOfPrims() @@ -1428,11 +1425,11 @@ Returns the number of prims in a link set the script is attached to key llGetNumberOfNotecardLines(string name) -Returns number of lines in notecard 'name' via the dataserver event (cast return value to integer) +Returns number of lines in notecard name via the dataserver event (cast return value to integer) list llGetBoundingBox(key object) -Returns the bounding box around an object (including any linked prims) relative to the root prim, in a list: [ (vector) min_corner, (vector) max_corner ] +Returns the bounding box around the object (including any linked prims) relative to its root prim, in a list in the format [ (vector) min_corner, (vector) max_corner ] vector llGetGeometricCenter() @@ -1440,142 +1437,143 @@ Returns the geometric center of the linked set the script is attached to. list llGetPrimitiveParams(list params) -Gets primitive parameters specified in the params list. +Returns the primitive parameters specified in the params list. string llIntegerToBase64(integer number) -Big endian encode of of integer as a Base64 string. +Returns a string that is a Base64 big endian encode of number integer llBase64ToInteger(string str) -Big endian decode of a Base64 string into an integer. +Returns an integer that is the str Base64 decoded as a big endian integer float llGetGMTclock() -Gets the time in seconds since midnight in GMT +Returns the time in seconds since midnight GMT string llGetSimulatorHostname() -Gets the hostname of the machine script is running on (same as string in viewer Help dialog) +Returns the hostname of the machine which the script is running on (same as string in viewer Help dialog) llSetLocalRot(rotation rot) -sets the rotation of a child prim relative to the root prim +Sets the rotation of a child prim relative to the root prim list llParseStringKeepNulls(string src, list separators, list spacers) -Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each), keeping any null values generated. +Breaks src into a list, discarding separators, keeping spacers, keeping any null values generated. +(separators and spacers must be lists of strings, maximum of 8 each) llRezAtRoot(string inventory, vector pos, vector vel, rotation rot, integer param) -Instantiate owner's inventory object at pos with velocity vel and rotation rot with start parameter param. -The last selected root object's location will be set to pos +Instantiates owner's inventory object rotated to rot with its root at pos, moving at vel, using param as the start parameter integer llGetObjectPermMask(integer mask) -Returns the requested permission mask for the root object the task is attached to. +Returns the requested permission mask for the root object the task is attached to llSetObjectPermMask(integer mask, integer value) -Sets the given permission mask to the new value on the root object the task is attached to. +Sets the given permission mask to the new value on the root object the task is attached to integer llGetInventoryPermMask(string item, integer mask) -Returns the requested permission mask for the inventory item. +Returns the requested permission mask for the inventory item llSetInventoryPermMask(string item, integer mask, integer value) -Sets the given permission mask to the new value on the inventory item. +Sets the given permission mask to the new value on the inventory item key llGetInventoryCreator(string item) -Returns the key for the creator of the inventory item. +Returns a key for the creator of the inventory item llOwnerSay(string msg) -says msg to owner only (if owner in sim) +Says msg to owner only. (Owner must be in the same region.) key llRequestSimulatorData(string simulator, integer data) -Requests data about simulator. When data is available the dataserver event will be raised +Requests data about simulator. When data is available the dataserver event will be raised. llForceMouselook(integer mouselook) -If mouselook is TRUE any avatar that sits on this object is forced into mouselook mode +If mouselook is TRUE, any avatar that sits upon the prim will be forced into mouselook mode float llGetObjectMass(key id) -Get the mass of the object with key id +Returns the mass of the avatar or object in the region list llListReplaceList(list dest, list src, integer start, integer end) -Replaces start through end of dest with src. +Returns a list that is dest with start through end removed and src inserted at start -llLoadURL(key avatar_id, string message, string url) -Shows dialog to avatar avatar_id offering to load web page at URL. If user clicks yes, launches their web browser. +llLoadURL(key avatar, string message, string url) +Shows a dialog to avatar offering to load the web page at url with a message. +If user clicks yes, launches the page in their web browser. llParcelMediaCommandList(list command) -Sends a list of commands, some with arguments, to a parcel. +Sends a list of commands, some with arguments, to a parcel to control the playback of movies and other media list llParcelMediaQuery(list query) -Sends a list of queries, returns a list of results. +Returns a list containing results of the sent query integer llModPow(integer a, integer b, integer c) -Returns a raised to the b power, mod c. ( (a**b)%c ). b is capped at 0xFFFF (16 bits). +Returns a raised to the b power, mod c. ( (a**b)%c ) +b is capped at 0xFFFF (16 bits). integer llGetInventoryType(string name) -Returns the type of the inventory name +Returns the type of the inventory item name llSetPayPrice(integer price, list quick_pay_buttons) -Sets the default amount when someone chooses to pay this object. +Sets the default amount on the dialog that appears when someone chooses to pay this prim vector llGetCameraPos() -Gets current camera position for agent task has permissions for. +Returns the current camera position for the agent the task has permissions for rotation llGetCameraRot() -Gets current camera orientation for agent task has permissions for. +Returns the current camera orientation for the agent the task has permissions for llSetPrimURL(string url) -Updates the URL for the web page shown on the sides of the object. +Updates the URL for the web page shown on the sides of the object llRefreshPrimURL() -Reloads the web page shown on the sides of the object. +Reloads the web page shown on the sides of the object string llEscapeURL(string url) -Returns and escaped/encoded version of url, replacing spaces with %20 etc. +Returns an escaped/encoded version of url, replacing spaces with %20 etc. string llUnescapeURL(string url) -Returns and unescaped/unencoded version of url, replacing %20 with spaces etc. +Returns an unescaped/ unencoded version of url, replacing %20 with spaces etc. llMapDestination(string simname, vector pos, vector look_at) -Opens world map centered on region with pos highlighted. +Opens the World Map centered on the region simname with pos highlighted. (NOTE: look_at currently does nothing.) Only works for scripts attached to avatar, or during touch events. -(NOTE: look_at currently does nothing) llAddToLandBanList(key avatar, float hours) -Add avatar to the land ban list for hours +Adds avatar to the land ban list for hours, or indefinitely if hours is 0 llRemoveFromLandPassList(key avatar) -Remove avatar from the land pass list +Removes avatar from the land pass list llRemoveFromLandBanList(key avatar) -Remove avatar from the land ban list +Removes avatar from the land ban list llSetCameraParams(list rules) @@ -1584,155 +1582,156 @@ List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] llClearCameraParams() -Resets all camera parameters to default values and turns off scripted camera control. +Resets all camera parameters to default values and turns off scripted camera control -float llListStatistics(integer operation, list l) -Perform statistical aggregate functions on list l using LIST_STAT_* operations. +float llListStatistics(integer operation, list src) +Performs statistical aggregate functions on list src using LIST_STAT_* operations integer llGetUnixTime() -Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock. +Returns the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock integer llGetParcelFlags(vector pos) -Get the parcel flags (PARCEL_FLAG_*) for the parcel including the point pos. +Returns a mask of the parcel flags (PARCEL_FLAG_*) for the parcel that includes the point pos integer llGetRegionFlags() -Get the region flags (REGION_FLAG_*) for the region the object is in. +Returns the region flags (REGION_FLAG_*) for the region the object is in string llXorBase64StringsCorrect(string s1, string s2) -Correctly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. +Correctly performs an exclusive or on two Base64 strings and returns a Base64 string. +s2 repeats if it is shorter than s1. llHTTPRequest(string url, list parameters, string body) -Send an HTTP request. +Sends an HTTP request to the specified url with the body of the request and parameters llResetLandBanList() -Removes all residents from the land ban list. +Removes all residents from the land ban list llResetLandPassList() -Removes all residents from the land access/pass list. +Removes all residents from the land access/pass list integer llGetObjectPrimCount(key object_id) -Returns the total number of prims for an object. +Returns the total number of prims for an object in the region list llGetParcelPrimOwners(vector pos) -Returns a list of all residents who own objects on the parcel and the number of objects they own. +Returns a list of all residents who own objects on the parcel at pos and with individual prim counts. Requires owner-like permissions for the parcel. integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide) -Gets the number of prims on the parcel of the given category. -Categories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP. +Returns the number of prims on the parcel at pos of the given category. +Categories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP integer llGetParcelMaxPrims(vector pos, integer sim_wide) -Gets the maximum number of prims allowed on the parcel at pos. +Returns the maximum number of prims allowed on the parcel at pos list llGetParcelDetails(vector pos, list params) -Gets the parcel details specified in params for the parcel at pos. +Returns the parcel details specified in params for the parcel at pos. Params is one or more of: PARCEL_DETAILS_NAME, _DESC, _OWNER, _GROUP, _AREA llSetLinkPrimitiveParams(integer linknumber, list rules) -Set primitive parameters for linknumber based on rules. +Sets primitive parameters for linknumber based on rules -llSetLinkTexture(integer link_pos, string texture, integer face) -Sets the texture of face for link_pos +llSetLinkTexture(integer linknumber, string texture, integer face) +Sets the texture of face for a task that exists in the link chain at linknumber string llStringTrim(string src, integer trim_type) -Trim leading and/or trailing spaces from a string. -Uses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL. +Trims the leading and/or trailing white spaces from a string. +trim_type can be STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL. llRegionSay(integer channel, string msg) -broadcasts msg to entire region on channel (not 0.) +Broadcasts msg on channel (not 0) that can be heard anywhere in the region by a script listening on channel list llGetObjectDetails(key id, list params) -Gets the object details specified in params for the object with key id. -Details are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR. +Returns the object details specified in params for the object with key id. +Params are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR llSetClickAction(integer action) -Sets the action performed when a prim is clicked upon. +Sets the action performed when a prim is clicked upon -int llGetRegionAgentCount() -returns the number of agents in a region +integer llGetRegionAgentCount() +Returns the number of avatars in the region llTextBox(key avatar, string message, integer chat_channel -Shows a dialog box on the avatar's screen with the message. -A text box asks for input, and if entered the text is chatted on chat_channel. +Shows a dialog box on the avatar's screen with the message. +It contains a text box for input, and if entered that text is chatted on chat_channel. -string llGetAgentLanguage(key id) -Gets the agents preferred language.. +string llGetAgentLanguage(key avatar) +Returns the language code of the preferred interface language of the avatar -vector llDetectedTouchUV(integer number) -returns the u and v coordinates in the first two components of a vector, for a triggered touch event +vector llDetectedTouchUV(integer index) +Returns the u and v coordinates in the first two components of a vector, for the texture coordinates where the prim was touched in a triggered touch event -integer llDetectedTouchFace(integer number) -returns the index of the face on the object for a triggered touch event +integer llDetectedTouchFace(integer index) +Returns the index of the face where the avatar clicked in a triggered touch event -vector llDetectedTouchPos(integer number) -returns the position touched for a triggered touch event +vector llDetectedTouchPos(integer index) +Returns the position where the object was touched in a triggered touch event -vector llDetectedTouchNormal(integer number) -returns the surface normal for a triggered touch event +vector llDetectedTouchNormal(integer index) +Returns the surface normal for a triggered touch event -vector llDetectedTouchBinormal(integer number) -returns the surface binormal for a triggered touch event +vector llDetectedTouchBinormal(integer index) +Returns the surface binormal for a triggered touch event -vector llDetectedTouchST(integer number) -returns the s and t coordinates in the first two components of a vector, for a triggered touch event +vector llDetectedTouchST(integer index) +Returns the s and t coordinates in the first two components of a vector, for the surface coordinates where the prim was touched in a triggered touch event -string llSHA1String(string sr) -Performs a SHA1 security Hash. Returns a 40 character hex string. +string llSHA1String(string src) +Returns a string of 40 hex characters that is the SHA1 security Hash of src integer llGetFreeURLs() -returns the available urls for the current script +Returns the number of available URLs for the current script key llRequestURL() -Requests one HTTP:// url for use by this object -Triggers an http_server event with results. +Requests one HTTP:// url for use by this object. +An http_request event is triggered with the results. key llRequestSecureURL() -Requests one HTTPS:// (SSL) url for use by this object -Triggers an http_server event with results. +Requests one HTTPS:// (SSL) url for use by this object. +An http_request event is triggered with the results. llReleaseURL(string url) -Releases the specified URL, it will no longer be usable. +Releases the specified URL, it will no longer be usable -llHTTPResponse(key id, integer status, string body) -Responds to request id with status and body. +llHTTPResponse(key request_id, integer status, string body) +Responds to request_id with status and body -string llGetHTTPHeader(key id, string header) -Get the value for header for request id. +string llGetHTTPHeader(key request_id, string header) +Returns the value for header for request_id -- cgit v1.2.3 From 706b67622a0581f58560e06d9ce1ca2722b31f9b Mon Sep 17 00:00:00 2001 From: Ramzi Ramey Date: Wed, 30 Sep 2009 18:17:32 +0000 Subject: DEV-39781 VWR-15246: LSL compiler typo in the tooltip for 'attach' - edited 2 words in the file --- indra/newview/app_settings/keywords.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index eaf5213985..a6abde36e3 100644 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -40,7 +40,7 @@ not_at_rot_target not_at_rot_target():Result of LLRotTarget library function cal money money(key id, integer amount):Triggered when L$ is given to task email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task -attach attach(key id):Triggered when an agent attaches or detaches from agent +attach attach(key id):Triggered when task attaches or detaches from agent dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data moving_start moving_start():Triggered when task begins moving moving_end moving_end():Triggered when task stops moving -- cgit v1.2.3 From 6519828508cd0f9feee8154a6412c474bea046de Mon Sep 17 00:00:00 2001 From: Ramzi Ramey Date: Wed, 30 Sep 2009 21:59:50 +0000 Subject: DEV-14830 add'l fix Copy-paste caused duplicate control and widget names in the script errors checkbox & radio buttons; Need to fix this before code is written for it. Need a unique name= for localization --- indra/newview/skins/default/xui/en/panel_preferences_advanced.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 8f710545d5..06ecfdc995 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -261,17 +261,17 @@ My Avatar: label="Show script errors" layout="topleft" left="30" - name="first_person_avatar_visible" + name="show_script_errors" width="256" top_pad="10"/> Date: Thu, 1 Oct 2009 00:23:26 +0000 Subject: DEV-40702 update viewer2 vivox sdk to v3 --- indra/newview/viewer_manifest.py | 14 ++++++++++---- install.xml | 12 ++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e85fddbc99..aa6a144247 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -248,10 +248,12 @@ class WindowsManifest(ViewerManifest): # Vivox runtimes if self.prefix(src="vivox-runtime/i686-win32", dst=""): self.path("SLVoice.exe") - self.path("alut.dll") + self.path("libsndfile-1.dll") + self.path("zlib1.dll") self.path("vivoxsdk.dll") + self.path("vivoxplatform.dll") self.path("ortp.dll") - self.path("wrap_oal.dll") + self.path("vivoxoal.dll") self.end_prefix() # pull in the crash logger and updater from other projects @@ -461,10 +463,11 @@ class DarwinManifest(ViewerManifest): self.path("zh-Hans.lproj") # SLVoice and vivox lols - self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") - self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") + self.path("vivox-runtime/universal-darwin/libsndfile.dylib", "libsndfile.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxoal.dylib", "libvivoxoal.dylib") self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib") self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") # need to get the kdu dll from any of the build directories as well @@ -715,7 +718,10 @@ class Linux_i686Manifest(LinuxManifest): self.end_prefix() if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): self.path("libortp.so") + self.path("libsndfile.so.1") + self.path("libvivoxoal.so.1") self.path("libvivoxsdk.so") + self.path("libvivoxplatform.so") self.end_prefix("lib") class Linux_x86_64Manifest(LinuxManifest): diff --git a/install.xml b/install.xml index 6366b3104b..e5a59ff3b1 100644 --- a/install.xml +++ b/install.xml @@ -1301,23 +1301,23 @@ anguage Infrstructure (CLI) international standard darwin md5sum - 8675b5eedef038b514338b17f0e55961 + 3eb4b31e92e16567e2fa967df9f9b845 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-darwin-20090309.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-darwin-20090930a.tar.bz2 linux md5sum - 01573510dce7f380f44e561ef2f3dd9f + 61ab6acd1f4736c5260c492bb60c26af url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-linux-20090930a.tar.bz2 windows md5sum - 752daa90e07c05202d1f76980cb955eb + ad5737dbfab87a13b23451b68248b22a url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-windows-20090309.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-windows-20090930a.tar.bz2
-- cgit v1.2.3 From 8135ddac021d3ea1aba2100f862bdb58eff33d07 Mon Sep 17 00:00:00 2001 From: Ramzi Ramey Date: Thu, 1 Oct 2009 02:02:31 +0000 Subject: L10N: typo and inconsistency in a tooltip of panel_login.xml --- indra/newview/skins/default/xui/en/panel_login.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index e7fb3fa208..f2a7dc11c7 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -52,7 +52,7 @@ max_length="31" name="first_name_edit" select_on_focus="true" - tool_tip="Second Life First Name" + tool_tip="[SECOND_LIFE] First Name" top_pad="2" width="120" /> Date: Thu, 1 Oct 2009 02:35:53 +0000 Subject: svn merge -r 134922:134973 svn+ssh://svn.lindenlab.com/svn/linden/branches/media-on-a-prim/moap-7 Merging branches/media-on-a-prim/moap-7 down to viewer-2.0. --- etc/message.xml | 9 +- indra/llcommon/lllslconstants.h | 13 + indra/llplugin/llpluginclassmedia.cpp | 58 +- indra/llplugin/llpluginclassmedia.h | 15 +- indra/llplugin/llpluginmessage.cpp | 23 + indra/llplugin/llpluginmessage.h | 4 + indra/llplugin/llpluginprocesschild.cpp | 35 +- indra/llplugin/llpluginprocesschild.h | 1 + indra/llplugin/llpluginprocessparent.cpp | 8 +- indra/llplugin/llpluginprocessparent.h | 3 + indra/llprimitive/CMakeLists.txt | 9 + indra/llprimitive/llmediaentry.cpp | 597 ++++++++++++++++ indra/llprimitive/llmediaentry.h | 228 +++++++ indra/llprimitive/llprimitive.cpp | 1 + indra/llprimitive/lltextureentry.cpp | 196 +++++- indra/llprimitive/lltextureentry.h | 50 +- indra/llprimitive/tests/llmediaentry_test.cpp | 484 +++++++++++++ indra/llvfs/lldir_linux.cpp | 2 +- indra/llvfs/lldir_mac.cpp | 2 +- indra/llvfs/lldir_win32.cpp | 2 +- indra/lscript/lscript_compile/CMakeLists.txt | 2 + indra/lscript/lscript_compile/indra.l | 43 +- indra/lscript/lscript_library/lscript_library.cpp | 9 +- .../gstreamer010/media_plugin_gstreamer010.cpp | 5 +- .../quicktime/media_plugin_quicktime.cpp | 5 +- indra/media_plugins/webkit/media_plugin_webkit.cpp | 21 +- indra/newview/CMakeLists.txt | 18 +- indra/newview/app_settings/keywords.ini | 43 +- indra/newview/app_settings/settings.xml | 80 ++- indra/newview/lldrawable.cpp | 24 + indra/newview/lldrawable.h | 6 +- indra/newview/llface.cpp | 22 +- indra/newview/llface.h | 1 + indra/newview/llfloatermediabrowser.cpp | 5 +- indra/newview/llfloatermediasettings.cpp | 249 +++++++ indra/newview/llfloatermediasettings.h | 81 +++ indra/newview/llfloaterpreference.cpp | 4 +- indra/newview/llfloatertools.cpp | 683 +++++++++++++++++-- indra/newview/llfloatertools.h | 19 +- indra/newview/llfloaterurlentry.cpp | 34 +- indra/newview/llfloaterurlentry.h | 4 +- indra/newview/llfloaterwhitelistentry.cpp | 97 +++ indra/newview/llfloaterwhitelistentry.h | 56 ++ indra/newview/llmediactrl.cpp | 162 +++-- indra/newview/llmediactrl.h | 20 +- indra/newview/llpanelcontents.cpp | 15 +- indra/newview/llpanelcontents.h | 18 +- indra/newview/llpanelface.cpp | 69 +- indra/newview/llpanelface.h | 9 +- indra/newview/llpanellandmedia.cpp | 11 +- indra/newview/llpanellandmedia.h | 9 - indra/newview/llpanellogin.cpp | 1 + indra/newview/llpanelmediasettingsgeneral.cpp | 409 +++++++++++ indra/newview/llpanelmediasettingsgeneral.h | 89 +++ indra/newview/llpanelmediasettingspermissions.cpp | 223 ++++++ indra/newview/llpanelmediasettingspermissions.h | 71 ++ indra/newview/llpanelmediasettingssecurity.cpp | 233 +++++++ indra/newview/llpanelmediasettingssecurity.h | 64 ++ indra/newview/llselectmgr.cpp | 101 ++- indra/newview/llselectmgr.h | 4 +- indra/newview/llspatialpartition.cpp | 5 + indra/newview/llspatialpartition.h | 1 + indra/newview/lltool.cpp | 16 +- indra/newview/lltoolpie.cpp | 95 ++- indra/newview/lltoolpie.h | 9 + indra/newview/llviewerfloaterreg.cpp | 4 + indra/newview/llviewermedia.cpp | 747 +++++++++++++++++---- indra/newview/llviewermedia.h | 96 ++- indra/newview/llviewermediafocus.cpp | 41 +- indra/newview/llviewermediafocus.h | 4 + indra/newview/llviewerobject.cpp | 107 ++- indra/newview/llviewerobject.h | 16 +- indra/newview/llviewerparcelmedia.cpp | 17 +- indra/newview/llviewerregion.cpp | 2 + indra/newview/llviewertexture.cpp | 465 +++++++++++-- indra/newview/llviewertexture.h | 68 +- indra/newview/llvovolume.cpp | 418 +++++++++++- indra/newview/llvovolume.h | 29 +- .../default/xui/en/floater_media_settings.xml | 20 + .../newview/skins/default/xui/en/floater_tools.xml | 249 +++++-- .../default/xui/en/floater_whitelist_entry.xml | 24 + .../newview/skins/default/xui/en/notifications.xml | 41 ++ indra/newview/skins/default/xui/en/panel_login.xml | 3 +- .../xui/en/panel_media_settings_general.xml | 199 ++++++ .../xui/en/panel_media_settings_permissions.xml | 49 ++ .../xui/en/panel_media_settings_security.xml | 56 ++ indra/newview/skins/default/xui/en/strings.xml | 18 +- indra/newview/viewer_manifest.py | 17 +- 88 files changed, 6906 insertions(+), 669 deletions(-) create mode 100644 indra/llprimitive/llmediaentry.cpp create mode 100644 indra/llprimitive/llmediaentry.h create mode 100644 indra/llprimitive/tests/llmediaentry_test.cpp create mode 100644 indra/newview/llfloatermediasettings.cpp create mode 100644 indra/newview/llfloatermediasettings.h create mode 100644 indra/newview/llfloaterwhitelistentry.cpp create mode 100644 indra/newview/llfloaterwhitelistentry.h create mode 100644 indra/newview/llpanelmediasettingsgeneral.cpp create mode 100644 indra/newview/llpanelmediasettingsgeneral.h create mode 100644 indra/newview/llpanelmediasettingspermissions.cpp create mode 100644 indra/newview/llpanelmediasettingspermissions.h create mode 100644 indra/newview/llpanelmediasettingssecurity.cpp create mode 100644 indra/newview/llpanelmediasettingssecurity.h create mode 100644 indra/newview/skins/default/xui/en/floater_media_settings.xml create mode 100644 indra/newview/skins/default/xui/en/floater_whitelist_entry.xml create mode 100644 indra/newview/skins/default/xui/en/panel_media_settings_general.xml create mode 100644 indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml create mode 100644 indra/newview/skins/default/xui/en/panel_media_settings_security.xml diff --git a/etc/message.xml b/etc/message.xml index dd1fda059e..d2ba9843e4 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -668,7 +668,14 @@ FetchLib true - + + ObjectMedia + false + + ObjectMediaNavigate + false + + messageBans diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h index a626e3f085..78f4435ed7 100644 --- a/indra/llcommon/lllslconstants.h +++ b/indra/llcommon/lllslconstants.h @@ -202,5 +202,18 @@ const U32 CHANGED_OWNER = 0x80; const U32 CHANGED_REGION = 0x100; const U32 CHANGED_TELEPORT = 0x200; const U32 CHANGED_REGION_START = 0x400; +const U32 CHANGED_MEDIA = 0x800; + +// Possible error results +const U32 LSL_STATUS_OK = 0; +const U32 LSL_STATUS_MALFORMED_PARAMS = 1000; +const U32 LSL_STATUS_TYPE_MISMATCH = 1001; +const U32 LSL_STATUS_BOUNDS_ERROR = 1002; +const U32 LSL_STATUS_NOT_FOUND = 1003; +const U32 LSL_STATUS_NOT_SUPPORTED = 1004; +const U32 LSL_STATUS_INTERNAL_ERROR = 1999; + +// Start per-function errors below, starting at 2000: +const U32 LSL_STATUS_WHITELIST_FAILED = 2001; #endif diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 54f153d182..7299ede22d 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -99,6 +99,8 @@ void LLPluginClassMedia::reset() mSetMediaHeight = -1; mRequestedMediaWidth = 0; mRequestedMediaHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; mTextureWidth = 0; mTextureHeight = 0; mMediaWidth = 0; @@ -266,8 +268,16 @@ unsigned char* LLPluginClassMedia::getBitsData() void LLPluginClassMedia::setSize(int width, int height) { - mSetMediaWidth = width; - mSetMediaHeight = height; + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } setSizeInternal(); } @@ -279,16 +289,26 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaWidth = mSetMediaWidth; mRequestedMediaHeight = mSetMediaHeight; } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } else { mRequestedMediaWidth = mDefaultMediaWidth; mRequestedMediaHeight = mDefaultMediaHeight; } + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + if(mAllowDownsample) { switch(mPriority) { + case PRIORITY_SLIDESHOW: case PRIORITY_LOW: // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) @@ -309,6 +329,12 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); } + + if(mRequestedMediaWidth > 2048) + mRequestedMediaWidth = 2048; + + if(mRequestedMediaHeight > 2048) + mRequestedMediaHeight = 2048; } void LLPluginClassMedia::setAutoScale(bool auto_scale) @@ -519,6 +545,10 @@ void LLPluginClassMedia::setPriority(EPriority priority) std::string priority_string; switch(priority) { + case PRIORITY_UNLOADED: + priority_string = "unloaded"; + mSleepTime = 1.0f; + break; case PRIORITY_STOPPED: priority_string = "stopped"; mSleepTime = 1.0f; @@ -527,6 +557,10 @@ void LLPluginClassMedia::setPriority(EPriority priority) priority_string = "hidden"; mSleepTime = 1.0f; break; + case PRIORITY_SLIDESHOW: + priority_string = "slideshow"; + mSleepTime = 1.0f; + break; case PRIORITY_LOW: priority_string = "low"; mSleepTime = 1.0f / 50.0f; @@ -550,6 +584,8 @@ void LLPluginClassMedia::setPriority(EPriority priority) mPlugin->setSleepTime(mSleepTime); } + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + // This may affect the calculated size, so recalculate it here. setSizeInternal(); } @@ -557,15 +593,27 @@ void LLPluginClassMedia::setPriority(EPriority priority) void LLPluginClassMedia::setLowPrioritySizeLimit(int size) { - if(mLowPrioritySizeLimit != size) + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) { - mLowPrioritySizeLimit = size; + mLowPrioritySizeLimit = power; // This may affect the calculated size, so recalculate it here. setSizeInternal(); } } +F64 LLPluginClassMedia::getCPUUsage() +{ + F64 result = 0.0f; + + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } + + return result; +} void LLPluginClassMedia::cut() { @@ -722,7 +770,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mNaturalMediaWidth = width; mNaturalMediaHeight = height; - setSize(width, height); + setSizeInternal(); } else if(message_name == "size_change_response") { diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 665a423d07..331ca5f6dc 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -66,6 +66,8 @@ public: int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; int getTextureWidth() const; int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; // This may return NULL. Callers need to check for and handle this case. unsigned char* getBitsData(); @@ -138,9 +140,11 @@ public: typedef enum { + PRIORITY_UNLOADED, // media plugin isn't even loaded. PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_LOW, // media is in the far distance, may be rendered at reduced size + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size PRIORITY_NORMAL, // normal (default) priority PRIORITY_HIGH // media has user focus and/or is taking up most of the screen }EPriority; @@ -148,6 +152,8 @@ public: void setPriority(EPriority priority); void setLowPrioritySizeLimit(int size); + F64 getCPUUsage(); + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event std::string getCursorName() const { return mCursorName; }; @@ -230,6 +236,7 @@ public: void initializeUrlHistory(const LLSD& url_history); protected: + LLPluginClassMediaOwner *mOwner; // Notify this object's owner that an event has occurred. @@ -266,7 +273,11 @@ protected: int mSetMediaWidth; int mSetMediaHeight; - // Actual media size being set (may be affected by auto-scale) + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) int mRequestedMediaWidth; int mRequestedMediaHeight; diff --git a/indra/llplugin/llpluginmessage.cpp b/indra/llplugin/llpluginmessage.cpp index bfabc5b7ca..e7412a1d8f 100644 --- a/indra/llplugin/llpluginmessage.cpp +++ b/indra/llplugin/llpluginmessage.cpp @@ -33,6 +33,7 @@ #include "llpluginmessage.h" #include "llsdserialize.h" +#include "u64.h" LLPluginMessage::LLPluginMessage() { @@ -93,6 +94,14 @@ void LLPluginMessage::setValueReal(const std::string &key, F64 value) mMessage["params"][key] = value; } +void LLPluginMessage::setValuePointer(const std::string &key, void* value) +{ + std::stringstream temp; + // iostreams should output pointer values in hex with an initial 0x by default. + temp << value; + setValue(key, temp.str()); +} + std::string LLPluginMessage::getClass(void) const { return mMessage["class"]; @@ -189,6 +198,20 @@ F64 LLPluginMessage::getValueReal(const std::string &key) const return result; } +void* LLPluginMessage::getValuePointer(const std::string &key) const +{ + void* result = NULL; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (void*)llstrtou64(value.c_str(), NULL, 16); + } + + return result; +} + std::string LLPluginMessage::generate(void) const { std::ostringstream result; diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index a17ec4bb98..f1a0e7c624 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -57,6 +57,7 @@ public: void setValueU32(const std::string &key, U32 value); void setValueBoolean(const std::string &key, bool value); void setValueReal(const std::string &key, F64 value); + void setValuePointer(const std::string &key, void *value); std::string getClass(void) const; std::string getName(void) const; @@ -82,6 +83,9 @@ public: // get the value of a key as a float. F64 getValueReal(const std::string &key) const; + // get the value of a key as a pointer. + void* getValuePointer(const std::string &key) const; + // Flatten the message into a string std::string generate(void) const; diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index dc51671032..450dcb3c78 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -43,6 +43,7 @@ LLPluginProcessChild::LLPluginProcessChild() mInstance = NULL; mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); mSleepTime = 1.0f / 100.0f; // default: send idle messages at 100Hz + mCPUElapsed = 0.0f; } LLPluginProcessChild::~LLPluginProcessChild() @@ -130,6 +131,7 @@ void LLPluginProcessChild::idle(void) { mHeartbeat.start(); mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; setState(STATE_PLUGIN_LOADED); } else @@ -158,10 +160,22 @@ void LLPluginProcessChild::idle(void) mInstance->idle(); - if(mHeartbeat.checkExpirationAndReset(HEARTBEAT_SECONDS)) + if(mHeartbeat.hasExpired()) { + // This just proves that we're not stuck down inside the plugin code. - sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat")); + LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); + + // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. + // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. + // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. + heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); + + sendMessageToParent(heartbeat); + + mHeartbeat.reset(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; } } // receivePluginMessage will transition to STATE_UNLOADING @@ -253,8 +267,11 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; - + LLTimer elapsed; + mInstance->sendMessage(buffer); + + mCPUElapsed += elapsed.getElapsedTimeF64(); } void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) @@ -317,12 +334,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) LLPluginMessage message("base", "shm_added"); message.setValue("name", name); message.setValueS32("size", (S32)size); - // shm address is split into 2x32bit values because LLSD doesn't serialize 64bit values and we need to support 64-bit addressing. - void * address = region->getMappedAddress(); - U32 address_lo = (U32)(U64(address) & 0xFFFFFFFF); // Extract the lower 32 bits - U32 address_hi = (U32)((U64(address)>>32) & 0xFFFFFFFF); // Extract the higher 32 bits - message.setValueU32("address", address_lo); - message.setValueU32("address_1", address_hi); + message.setValuePointer("address", region->getMappedAddress()); sendMessageToPlugin(message); // and send the response to the parent @@ -380,7 +392,11 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) if(passMessage && mInstance != NULL) { + LLTimer elapsed; + mInstance->sendMessage(message); + + mCPUElapsed += elapsed.getElapsedTimeF64(); } } @@ -454,6 +470,7 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message) if(passMessage) { + LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; writeMessageRaw(message); } } diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index f92905e8bd..75860bdf0a 100644 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -102,6 +102,7 @@ private: LLTimer mHeartbeat; F64 mSleepTime; + F64 mCPUElapsed; }; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index f18a117dde..41784a713c 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -38,7 +38,7 @@ #include "llapr.h" // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. -static const F32 PLUGIN_LOCKED_UP_SECONDS = 10.0f; +static const F32 PLUGIN_LOCKED_UP_SECONDS = 15.0f; // Somewhat longer timeout for initial launch. static const F32 PLUGIN_LAUNCH_SECONDS = 20.0f; @@ -87,6 +87,7 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std { mProcess.setExecutable(launcher_filename); mPluginFile = plugin_filename; + mCPUUsage = 0.0f; setState(STATE_INITIALIZED); } @@ -503,6 +504,11 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { // this resets our timer. mHeartbeat.setTimerExpirySec(PLUGIN_LOCKED_UP_SECONDS); + + mCPUUsage = message.getValueReal("cpu_usage"); + + LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; + } else if(message_name == "shm_add_response") { diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 545eb85c9a..0d0b047c88 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -96,6 +96,8 @@ public: bool getDisableTimeout() { return mDisableTimeout; }; void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; + F64 getCPUUsage() { return mCPUUsage; }; + private: enum EState @@ -140,6 +142,7 @@ private: LLTimer mHeartbeat; F64 mSleepTime; + F64 mCPUUsage; bool mDisableTimeout; }; diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 478dd398ff..d130513637 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories( set(llprimitive_SOURCE_FILES llmaterialtable.cpp + llmediaentry.cpp llprimitive.cpp llprimtexturelist.cpp lltextureanim.cpp @@ -31,6 +32,7 @@ set(llprimitive_HEADER_FILES legacy_object_types.h llmaterialtable.h + llmediaentry.h llprimitive.h llprimtexturelist.h lltextureanim.h @@ -49,3 +51,10 @@ set_source_files_properties(${llprimitive_HEADER_FILES} list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES}) add_library (llprimitive ${llprimitive_SOURCE_FILES}) + +#add unit tests +INCLUDE(LLAddBuildTest) +SET(llprimitive_TEST_SOURCE_FILES + llmediaentry.cpp + ) +LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp new file mode 100644 index 0000000000..fa04bf80e7 --- /dev/null +++ b/indra/llprimitive/llmediaentry.cpp @@ -0,0 +1,597 @@ +/** + * @file llmediaentry.cpp + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmediaentry.h" +#include "lllslconstants.h" + +#include + +// LLSD key defines +// DO NOT REORDER OR REMOVE THESE! + +// Some LLSD keys. Do not change! +#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable" +#define MEDIA_CONTROLS_KEY_STR "controls" +#define MEDIA_CURRENT_URL_KEY_STR "current_url" +#define MEDIA_HOME_URL_KEY_STR "home_url" +#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop" +#define MEDIA_AUTO_PLAY_KEY_STR "auto_play" +#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale" +#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom" +#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact" +#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels" +#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels" + +// "security" fields +#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable" +#define MEDIA_WHITELIST_KEY_STR "whitelist" + +// "permissions" fields +#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact" +#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control" + +// "general" fields +const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR; +const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR; +const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR; +const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR; +const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR; +const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR; +const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR; +const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR; +const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR; +const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR; +const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR; + +// "security" fields +const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR; +const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR; + +// "permissions" fields +const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR; +const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR; + +#define DEFAULT_URL_PREFIX "http://" + +// Constructor(s) +LLMediaEntry::LLMediaEntry() : + mAltImageEnable(false), + mControls(STANDARD), + mCurrentURL(""), + mHomeURL(""), + mAutoLoop(false), + mAutoPlay(false), + mAutoScale(false), + mAutoZoom(false), + mFirstClickInteract(false), + mWidthPixels(0), + mHeightPixels(0), + mWhiteListEnable(false), + // mWhiteList + mPermsInteract(PERM_ALL), + mPermsControl(PERM_ALL), + mMediaIDp(NULL) +{ +} + +LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) : + mMediaIDp(NULL) +{ + // "general" fields + mAltImageEnable = rhs.mAltImageEnable; + mControls = rhs.mControls; + mCurrentURL = rhs.mCurrentURL; + mHomeURL = rhs.mHomeURL; + mAutoLoop = rhs.mAutoLoop; + mAutoPlay = rhs.mAutoPlay; + mAutoScale = rhs.mAutoScale; + mAutoZoom = rhs.mAutoZoom; + mFirstClickInteract = rhs.mFirstClickInteract; + mWidthPixels = rhs.mWidthPixels; + mHeightPixels = rhs.mHeightPixels; + + // "security" fields + mWhiteListEnable = rhs.mWhiteListEnable; + mWhiteList = rhs.mWhiteList; + + // "permissions" fields + mPermsInteract = rhs.mPermsInteract; + mPermsControl = rhs.mPermsControl; +} + +LLMediaEntry::~LLMediaEntry() +{ + if (NULL != mMediaIDp) + { + delete mMediaIDp; + } +} + +LLSD LLMediaEntry::asLLSD() const +{ + LLSD sd; + asLLSD(sd); + return sd; +} + +// +// LLSD functions +// +void LLMediaEntry::asLLSD(LLSD& sd) const +{ + // "general" fields + sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable; + sd[CONTROLS_KEY] = (LLSD::Integer)mControls; + sd[CURRENT_URL_KEY] = mCurrentURL; + sd[HOME_URL_KEY] = mHomeURL; + sd[AUTO_LOOP_KEY] = mAutoLoop; + sd[AUTO_PLAY_KEY] = mAutoPlay; + sd[AUTO_SCALE_KEY] = mAutoScale; + sd[AUTO_ZOOM_KEY] = mAutoZoom; + sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract; + sd[WIDTH_PIXELS_KEY] = mWidthPixels; + sd[HEIGHT_PIXELS_KEY] = mHeightPixels; + + // "security" fields + sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable; + for (U32 i=0; i &whitelist ) +{ + // *NOTE: This code is VERY similar to the setWhitelist below. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First count to make sure the size constraint is not violated + std::vector::const_iterator iter = whitelist.begin(); + std::vector::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.begin(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setWhiteList( const LLSD &whitelist ) +{ + // If whitelist is undef, this is a no-op. + if (whitelist.isUndefined()) return LSL_STATUS_OK; + + // However, if the whitelist is an empty array, erase it. + if (whitelist.isArray()) + { + // *NOTE: This code is VERY similar to the setWhitelist above. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First check to make sure the size and count constraints are not violated + LLSD::array_const_iterator iter = whitelist.beginArray(); + LLSD::array_const_iterator end = whitelist.endArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.beginArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; + } + else + { + return LSL_STATUS_MALFORMED_PARAMS; + } +} + + +static void prefix_with(std::string &str, const char *chars, const char *prefix) +{ + // Given string 'str', prefix all instances of any character in 'chars' + // with 'prefix' + size_t found = str.find_first_of(chars); + size_t prefix_len = strlen(prefix); + while (found != std::string::npos) + { + str.insert(found, prefix, prefix_len); + found = str.find_first_of(chars, found+prefix_len+1); + } +} + +static bool pattern_match(const std::string &candidate_str, const std::string &pattern) +{ + // If the pattern is empty, it matches + if (pattern.empty()) return true; + + // 'pattern' is a glob pattern, we only accept '*' chars + // copy it + std::string expression = pattern; + + // Escape perl's regexp chars with a backslash, except all "*" chars + prefix_with(expression, ".[{()\\+?|^$", "\\"); + prefix_with(expression, "*", "."); + + // case-insensitive matching: + boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); + return boost::regex_match(candidate_str, regexp); +} + +bool LLMediaEntry::checkCandidateUrl(const std::string& url) const +{ + if (getWhiteListEnable()) + { + return checkUrlAgainstWhitelist(url, getWhiteList()); + } + else + { + return true; + } +} + +// static +bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url, + const std::vector &whitelist) +{ + bool passes = true; + // *NOTE: no entries? Don't check + if (whitelist.size() > 0) + { + passes = false; + + // Case insensitive: the reason why we toUpper both this and the + // filter + std::string candidate_url = url; + // Use lluri to see if there is a path part in the candidate URL. No path? Assume "/" + LLURI candidate_uri(candidate_url); + std::vector::const_iterator iter = whitelist.begin(); + std::vector::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter ) + { + std::string filter = *iter; + + LLURI filter_uri(filter); + bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() ); + if (filter_uri.scheme().empty()) + { + filter_uri = LLURI(DEFAULT_URL_PREFIX + filter); + } + bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() ); + bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() ); + + if (scheme_passes && authority_passes && path_passes) + { + passes = true; + break; + } + } + } + return passes; +} + +U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ) +{ + if ( value.length() > limit ) + { + return LSL_STATUS_BOUNDS_ERROR; + } + else + { + field = value; + return LSL_STATUS_OK; + } +} + +U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls) +{ + if (controls == STANDARD || + controls == MINI) + { + mControls = controls; + return LSL_STATUS_OK; + } + return LSL_STATUS_BOUNDS_ERROR; +} + +U32 LLMediaEntry::setPermsInteract( U8 val ) +{ + mPermsInteract = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setPermsControl( U8 val ) +{ + mPermsControl = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setCurrentURL(const std::string& current_url) +{ + return setCurrentURLInternal( current_url, true ); +} + +U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist) +{ + if ( ! check_whitelist || checkCandidateUrl(current_url)) + { + return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH ); + } + else + { + return LSL_STATUS_WHITELIST_FAILED; + } +} + +U32 LLMediaEntry::setHomeURL(const std::string& home_url) +{ + return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH ); +} + +U32 LLMediaEntry::setWidthPixels(U16 width) +{ + if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mWidthPixels = width; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setHeightPixels(U16 height) +{ + if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mHeightPixels = height; + return LSL_STATUS_OK; +} + +const LLUUID &LLMediaEntry::getMediaID() const +{ + // Lazily generate media ID + if (NULL == mMediaIDp) + { + mMediaIDp = new LLUUID(); + mMediaIDp->generate(); + } + return *mMediaIDp; +} + diff --git a/indra/llprimitive/llmediaentry.h b/indra/llprimitive/llmediaentry.h new file mode 100644 index 0000000000..2a5486666a --- /dev/null +++ b/indra/llprimitive/llmediaentry.h @@ -0,0 +1,228 @@ +/** + * @file llmediaentry.h + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLMEDIAENTRY_H +#define LL_LLMEDIAENTRY_H + +#include "llsd.h" +#include "llstring.h" + +// For return values of set* +#include "lllslconstants.h" + +class LLMediaEntry +{ +public: + enum MediaControls { + STANDARD = 0, + MINI + }; + + // Constructors + LLMediaEntry(); + LLMediaEntry(const LLMediaEntry &rhs); + + LLMediaEntry &operator=(const LLMediaEntry &rhs); + virtual ~LLMediaEntry(); + + bool operator==(const LLMediaEntry &rhs) const; + bool operator!=(const LLMediaEntry &rhs) const; + + // Render as LLSD + LLSD asLLSD() const; + void asLLSD(LLSD& sd) const; + operator LLSD() const { return asLLSD(); } + // Returns false iff the given LLSD contains fields that violate any bounds + // limits. + static bool checkLLSD(const LLSD& sd); + // This doesn't merge, it overwrites the data, so will use + // LLSD defaults if need be. Note: does not check limits! + // Use checkLLSD() above first to ensure the LLSD is valid. + void fromLLSD(const LLSD& sd); + // This merges data from the incoming LLSD into our fields. + // Note that it also does NOT check limits! Use checkLLSD() above first. + void mergeFromLLSD(const LLSD& sd); + + // "general" fields + bool getAltImageEnable() const { return mAltImageEnable; } + MediaControls getControls() const { return mControls; } + std::string getCurrentURL() const { return mCurrentURL; } + std::string getHomeURL() const { return mHomeURL; } + bool getAutoLoop() const { return mAutoLoop; } + bool getAutoPlay() const { return mAutoPlay; } + bool getAutoScale() const { return mAutoScale; } + bool getAutoZoom() const { return mAutoZoom; } + bool getFirstClickInteract() const { return mFirstClickInteract; } + U16 getWidthPixels() const { return mWidthPixels; } + U16 getHeightPixels() const { return mHeightPixels; } + + // "security" fields + bool getWhiteListEnable() const { return mWhiteListEnable; } + const std::vector &getWhiteList() const { return mWhiteList; } + + // "permissions" fields + U8 getPermsInteract() const { return mPermsInteract; } + U8 getPermsControl() const { return mPermsControl; } + + // Setters. Those that return a U32 return a status error code + // See lllslconstants.h + + // "general" fields + U32 setAltImageEnable(bool alt_image_enable) { mAltImageEnable = alt_image_enable; return LSL_STATUS_OK; } + U32 setControls(MediaControls controls); + U32 setCurrentURL(const std::string& current_url); + U32 setHomeURL(const std::string& home_url); + U32 setAutoLoop(bool auto_loop) { mAutoLoop = auto_loop; return LSL_STATUS_OK; } + U32 setAutoPlay(bool auto_play) { mAutoPlay = auto_play; return LSL_STATUS_OK; } + U32 setAutoScale(bool auto_scale) { mAutoScale = auto_scale; return LSL_STATUS_OK; } + U32 setAutoZoom(bool auto_zoom) { mAutoZoom = auto_zoom; return LSL_STATUS_OK; } + U32 setFirstClickInteract(bool first_click) { mFirstClickInteract = first_click; return LSL_STATUS_OK; } + U32 setWidthPixels(U16 width); + U32 setHeightPixels(U16 height); + + // "security" fields + U32 setWhiteListEnable( bool whitelist_enable ) { mWhiteListEnable = whitelist_enable; return LSL_STATUS_OK; } + U32 setWhiteList( const std::vector &whitelist ); + U32 setWhiteList( const LLSD &whitelist ); // takes an LLSD array + + // "permissions" fields + U32 setPermsInteract( U8 val ); + U32 setPermsControl( U8 val ); + + const LLUUID& getMediaID() const; + + // Helper function to check a candidate URL against the whitelist + // Returns true iff candidate URL passes (or if there is no whitelist), false otherwise + bool checkCandidateUrl(const std::string& url) const; + +public: + // Static function to check a URL against a whitelist + // Returns true iff url passes the given whitelist + static bool checkUrlAgainstWhitelist(const std::string &url, + const std::vector &whitelist); + +public: + // LLSD key defines + // "general" fields + static const char* ALT_IMAGE_ENABLE_KEY; + static const char* CONTROLS_KEY; + static const char* CURRENT_URL_KEY; + static const char* HOME_URL_KEY; + static const char* AUTO_LOOP_KEY; + static const char* AUTO_PLAY_KEY; + static const char* AUTO_SCALE_KEY; + static const char* AUTO_ZOOM_KEY; + static const char* FIRST_CLICK_INTERACT_KEY; + static const char* WIDTH_PIXELS_KEY; + static const char* HEIGHT_PIXELS_KEY; + + // "security" fields + static const char* WHITELIST_ENABLE_KEY; + static const char* WHITELIST_KEY; + + // "permissions" fields + static const char* PERMS_INTERACT_KEY; + static const char* PERMS_CONTROL_KEY; + + // Field enumerations & constants + + // *NOTE: DO NOT change the order of these, and do not insert values + // in the middle! + // Add values to the end, and make sure to change PARAM_MAX_ID! + enum Fields { + ALT_IMAGE_ENABLE_ID = 0, + CONTROLS_ID = 1, + CURRENT_URL_ID = 2, + HOME_URL_ID = 3, + AUTO_LOOP_ID = 4, + AUTO_PLAY_ID = 5, + AUTO_SCALE_ID = 6, + AUTO_ZOOM_ID = 7, + FIRST_CLICK_INTERACT_ID = 8, + WIDTH_PIXELS_ID = 9, + HEIGHT_PIXELS_ID = 10, + WHITELIST_ENABLE_ID = 11, + WHITELIST_ID = 12, + PERMS_INTERACT_ID = 13, + PERMS_CONTROL_ID = 14, + PARAM_MAX_ID = PERMS_CONTROL_ID + }; + + // "permissions" values + // (e.g. (PERM_OWNER | PERM_GROUP) sets permissions on for OWNER and GROUP + static const U8 PERM_NONE = 0x0; + static const U8 PERM_OWNER = 0x1; + static const U8 PERM_GROUP = 0x2; + static const U8 PERM_ANYONE = 0x4; + static const U8 PERM_ALL = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + static const U8 PERM_MASK = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + + // Limits (in bytes) + static const U32 MAX_URL_LENGTH = 1024; + static const U32 MAX_WHITELIST_SIZE = 1024; + static const U32 MAX_WHITELIST_COUNT = 64; + static const U16 MAX_WIDTH_PIXELS = 2048; + static const U16 MAX_HEIGHT_PIXELS = 2048; + +private: + + U32 setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ); + U32 setCurrentURLInternal( const std::string &url, bool check_whitelist); + bool fromLLSDInternal(const LLSD &sd, bool overwrite); + +private: + // "general" fields + bool mAltImageEnable; + MediaControls mControls; + std::string mCurrentURL; + std::string mHomeURL; + bool mAutoLoop; + bool mAutoPlay; + bool mAutoScale; + bool mAutoZoom; + bool mFirstClickInteract; + U16 mWidthPixels; + U16 mHeightPixels; + + // "security" fields + bool mWhiteListEnable; + std::vector mWhiteList; + + // "permissions" fields + U8 mPermsInteract; + U8 mPermsControl; + + mutable LLUUID *mMediaIDp; // temporary id assigned to media on the viewer +}; + +#endif + diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index b925d97b5c..b102254b62 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1134,6 +1134,7 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); + } return retval; diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 3bcd831142..b534939dfc 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -32,13 +32,31 @@ #include "linden_common.h" +#include "lluuid.h" +#include "llmediaentry.h" #include "lltextureentry.h" #include "llsdutil.h" +#include "v4color.h" const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess const LLTextureEntry LLTextureEntry::null; +// Some LLSD keys. Do not change these! +#define OBJECT_ID_KEY_STR "object_id" +#define TEXTURE_INDEX_KEY_STR "texture_index" +#define OBJECT_MEDIA_VERSION_KEY_STR "object_media_version" +#define OBJECT_MEDIA_DATA_KEY_STR "object_media_data" +#define TEXTURE_MEDIA_DATA_KEY_STR "media_data" + +/*static*/ const char* LLTextureEntry::OBJECT_ID_KEY = OBJECT_ID_KEY_STR; +/*static*/ const char* LLTextureEntry::OBJECT_MEDIA_DATA_KEY = OBJECT_MEDIA_DATA_KEY_STR; +/*static*/ const char* LLTextureEntry::MEDIA_VERSION_KEY = OBJECT_MEDIA_VERSION_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_INDEX_KEY = TEXTURE_INDEX_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_MEDIA_DATA_KEY = TEXTURE_MEDIA_DATA_KEY_STR; + +static const std::string MEDIA_VERSION_STRING_PREFIX = "x-mv:"; + // static LLTextureEntry* LLTextureEntry::newTextureEntry() { @@ -47,16 +65,19 @@ LLTextureEntry* LLTextureEntry::newTextureEntry() //=============================================================== LLTextureEntry::LLTextureEntry() + : mMediaEntry(NULL) { init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) + : mMediaEntry(NULL) { init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) + : mMediaEntry(NULL) { mID = rhs.mID; mScaleS = rhs.mScaleS; @@ -68,6 +89,10 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } } LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) @@ -84,6 +109,16 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } + else { + mMediaEntry = NULL; + } } return *this; @@ -103,10 +138,19 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of mGlow = 0; setColor(LLColor4(1.f, 1.f, 1.f, 1.f)); + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; } LLTextureEntry::~LLTextureEntry() { + if(mMediaEntry) + { + delete mMediaEntry; + mMediaEntry = NULL; + } } bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const @@ -158,10 +202,17 @@ void LLTextureEntry::asLLSD(LLSD& sd) const sd["bump"] = getBumpShiny(); sd["fullbright"] = getFullbright(); sd["media_flags"] = mMediaFlags; + if (hasMedia()) { + LLSD mediaData; + if (NULL != getMediaData()) { + getMediaData()->asLLSD(mediaData); + } + sd[TEXTURE_MEDIA_DATA_KEY] = mediaData; + } sd["glow"] = mGlow; } -bool LLTextureEntry::fromLLSD(LLSD& sd) +bool LLTextureEntry::fromLLSD(const LLSD& sd) { const char *w, *x; w = "imageid"; @@ -206,6 +257,17 @@ bool LLTextureEntry::fromLLSD(LLSD& sd) { setMediaTexGen( sd[w].asInteger() ); } else goto fail; + // If the "has media" flag doesn't match the fact that + // media data exists, updateMediaData will "fix" it + // by either clearing or setting the flag + w = TEXTURE_MEDIA_DATA_KEY; + if (hasMedia() != sd.has(w)) + { + llwarns << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() << + ") does not match presence of media_data (" << sd.has(w) << "). Fixing." << llendl; + } + updateMediaData(sd[w]); + w = "glow"; if (sd.has(w)) { @@ -370,7 +432,19 @@ S32 LLTextureEntry::setMediaTexGen(U8 media) if (mMediaFlags != media) { mMediaFlags = media; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } return TEM_CHANGE_NONE; } @@ -430,7 +504,19 @@ S32 LLTextureEntry::setMediaFlags(U8 media_flags) { mMediaFlags &= ~TEM_MEDIA_MASK; mMediaFlags |= media_flags; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } return TEM_CHANGE_NONE; } @@ -456,3 +542,107 @@ S32 LLTextureEntry::setGlow(F32 glow) } return TEM_CHANGE_NONE; } + +void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (NULL != mMediaEntry) + { + delete mMediaEntry; + } + mMediaEntry = new LLMediaEntry(media_entry); +} + +bool LLTextureEntry::updateMediaData(const LLSD& media_data) +{ + if (media_data.isUndefined()) + { + // clear the media data + clearMediaData(); + return false; + } + else { + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *clobber* all of the fields in mMediaEntry + // with whatever fields are present (or not present) in media_data! + mMediaEntry->fromLLSD(media_data); + return true; + } +} + +void LLTextureEntry::clearMediaData() +{ + mMediaFlags &= ~MF_HAS_MEDIA; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; +} + +void LLTextureEntry::mergeIntoMediaData(const LLSD& media_fields) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *merge* the data in media_fields + // with the data in our media entry + mMediaEntry->mergeFromLLSD(media_fields); +} + +//static +std::string LLTextureEntry::touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id) +{ + // XXX TODO: make media version string binary (base64-encoded?) + // Media "URL" is a representation of a version and the last-touched agent + // x-mv:nnnnn/agent-id + // where "nnnnn" is version number + // *NOTE: not the most efficient code in the world... + U32 current_version = getVersionFromMediaVersionString(in_version) + 1; + const size_t MAX_VERSION_LEN = 10; // 2^32 fits in 10 decimal digits + char buf[MAX_VERSION_LEN+1]; + snprintf(buf, (int)MAX_VERSION_LEN+1, "%0*u", (int)MAX_VERSION_LEN, current_version); // added int cast to fix warning/breakage on mac. + return MEDIA_VERSION_STRING_PREFIX + buf + "/" + agent_id.asString(); +} + +//static +U32 LLTextureEntry::getVersionFromMediaVersionString(const std::string &version_string) +{ + U32 version = 0; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + std::string v = version_string.substr(MEDIA_VERSION_STRING_PREFIX.length(), found); + version = strtoul(v.c_str(),NULL,10); + } + } + return version; +} + +//static +LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &version_string) +{ + LLUUID id; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + if (found != std::string::npos) + { + std::string v = version_string.substr(found + 1); + id.set(v); + } + } + } + return id; +} diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index 84870e93e6..8d2834f78c 100644 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -37,10 +37,13 @@ #include "v4color.h" #include "llsd.h" +// These bits are used while unpacking TEM messages to tell which aspects of +// the texture entry changed. const S32 TEM_CHANGE_NONE = 0x0; const S32 TEM_CHANGE_COLOR = 0x1; const S32 TEM_CHANGE_TEXTURE = 0x2; -const S32 TEM_INVALID = 0x4; +const S32 TEM_CHANGE_MEDIA = 0x4; +const S32 TEM_INVALID = 0x8; const S32 TEM_BUMPMAP_COUNT = 32; @@ -65,6 +68,8 @@ const S32 TEM_MEDIA_MASK = 0x01; const S32 TEM_TEX_GEN_MASK = 0x06; const S32 TEM_TEX_GEN_SHIFT = 1; +// forward declarations +class LLMediaEntry; class LLTextureEntry { @@ -92,7 +97,7 @@ public: LLSD asLLSD() const; void asLLSD(LLSD& sd) const; operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); + bool fromLLSD(const LLSD& sd); virtual LLTextureEntry* newBlank() const; virtual LLTextureEntry* newCopy() const; @@ -140,9 +145,35 @@ public: U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; } U8 getMediaTexGen() const { return mMediaFlags; } F32 getGlow() const { return mGlow; } - + + // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL. + // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData() + // to NOT return NULL. + bool hasMedia() const { return (bool)(mMediaFlags & MF_HAS_MEDIA); } + LLMediaEntry* getMediaData() const { return mMediaEntry; } + + // Completely change the media data on this texture entry. + void setMediaData(const LLMediaEntry &media_entry); + // Returns true if media data was updated, false if it was cleared + bool updateMediaData(const LLSD& media_data); + // Clears media data, and sets the media flags bit to 0 + void clearMediaData(); + // Merges the given LLSD of media fields with this media entry. + // Only those fields that are set that match the keys in + // LLMediaEntry will be affected. If no fields are set or if + // the LLSD is undefined, this is a no-op. + void mergeIntoMediaData(const LLSD& media_fields); + + // Takes a media version string (an empty string or a previously-returned string) + // and returns a "touched" string, touched by agent_id + static std::string touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id); + // Given a media version string, return the version + static U32 getVersionFromMediaVersionString(const std::string &version_string); + // Given a media version string, return the UUID of the agent + static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string); + // Media flags - enum { MF_NONE = 0x0, MF_WEB_PAGE = 0x1 }; + enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 }; public: F32 mScaleS; // S, T offset @@ -152,6 +183,14 @@ public: F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner static const LLTextureEntry null; + + // LLSD key defines + static const char* OBJECT_ID_KEY; + static const char* OBJECT_MEDIA_DATA_KEY; + static const char* MEDIA_VERSION_KEY; + static const char* TEXTURE_INDEX_KEY; + static const char* TEXTURE_MEDIA_DATA_KEY; + protected: LLUUID mID; // Texture GUID LLColor4 mColor; @@ -159,6 +198,9 @@ protected: U8 mMediaFlags; // replace with web page, movie, etc. F32 mGlow; + // Note the media data is not sent via the same message structure as the rest of the TE + LLMediaEntry* mMediaEntry; // The media data for the face + // NOTE: when adding new data to this class, in addition to adding it to the serializers asLLSD/fromLLSD and the // message packers (e.g. LLPrimitive::packTEMessage) you must also implement its copy in LLPrimitive::copyTEs() diff --git a/indra/llprimitive/tests/llmediaentry_test.cpp b/indra/llprimitive/tests/llmediaentry_test.cpp new file mode 100644 index 0000000000..72478d0459 --- /dev/null +++ b/indra/llprimitive/tests/llmediaentry_test.cpp @@ -0,0 +1,484 @@ +/** + * @file llmediaentry_test.cpp + * @brief llmediaentry unit tests + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * Copyright (c) 2001-2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "boost/lexical_cast.hpp" +#include "llstring.h" +#include "llsdutil.h" +#include "llsdserialize.h" + +#include "../llmediaentry.h" +#include "lllslconstants.h" + +#define DEFAULT_MEDIA_ENTRY "\n\ + \n\ + alt_image_enable\n\ + 0\n\ + auto_loop\n\ + 0\n\ + auto_play\n\ + 0\n\ + auto_scale\n\ + 0\n\ + auto_zoom\n\ + 0\n\ + controls\n\ + 0\n\ + current_url\n\ + \n\ + first_click_interact\n\ + 0\n\ + height_pixels\n\ + 0\n\ + home_url\n\ + \n\ + perms_control\n\ + 7\n\ + perms_interact\n\ + 7\n\ + whitelist_enable\n\ + 0\n\ + width_pixels\n\ + 0\n\ + \n\ + " + +#define EMPTY_MEDIA_ENTRY "\n\ + \n\ + alt_image_enable\n\ + 0\n\ + auto_loop\n\ + 0\n\ + auto_play\n\ + 0\n\ + auto_scale\n\ + 0\n\ + auto_zoom\n\ + 0\n\ + controls\n\ + 0\n\ + current_url\n\ + \n\ + first_click_interact\n\ + 0\n\ + height_pixels\n\ + 0\n\ + home_url\n\ + \n\ + perms_control\n\ + 0\n\ + perms_interact\n\ + 0\n\ + whitelist_enable\n\ + 0\n\ + width_pixels\n\ + 0\n\ + \n\ + " + +#define PARTIAL_MEDIA_ENTRY(CURRENT_URL) "\n\ + \n\ + alt_image_enable\n\ + 0\n\ + auto_loop\n\ + 0\n\ + auto_play\n\ + 0\n\ + auto_scale\n\ + 0\n\ + auto_zoom\n\ + 0\n\ + controls\n\ + 0\n\ + current_url\n\ + " CURRENT_URL "\n\ + first_click_interact\n\ + 0\n\ + height_pixels\n\ + 0\n\ + home_url\n\ + \n\ + perms_control\n\ + 0\n\ + perms_interact\n\ + 0\n\ + whitelist_enable\n\ + 0\n\ + width_pixels\n\ + 0\n\ + \n\ + " + +namespace tut +{ + // this is fixture data that gets created before each test and destroyed + // after each test. this is where we put all of the setup/takedown code + // and data needed for each test. + struct MediaEntry_test + { + MediaEntry_test() { + emptyMediaEntryStr = EMPTY_MEDIA_ENTRY; + std::istringstream e(EMPTY_MEDIA_ENTRY); + LLSDSerialize::fromXML(emptyMediaEntryLLSD, e); + defaultMediaEntryStr = DEFAULT_MEDIA_ENTRY; + std::istringstream d(DEFAULT_MEDIA_ENTRY); + LLSDSerialize::fromXML(defaultMediaEntryLLSD, d); + } + std::string emptyMediaEntryStr; + LLSD emptyMediaEntryLLSD; + std::string defaultMediaEntryStr; + LLSD defaultMediaEntryLLSD; + }; + + typedef test_group factory; + typedef factory::object object; +} + + +namespace +{ + // this is for naming our tests to make pretty output + tut::factory tf("MediaEntry Test"); +} + +namespace tut +{ + bool llsd_equals(const LLSD& a, const LLSD& b) { + // cheesy, brute force, but it works + return std::string(ll_pretty_print_sd(a)) == std::string(ll_pretty_print_sd(b)); + } + + void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual) + { + if (! llsd_equals(expected, actual)) + { + std::string message = msg; + message += ": actual: "; + message += ll_pretty_print_sd(actual); + message += "\n expected: "; + message += ll_pretty_print_sd(expected); + message += "\n"; + ensure(message, false); + } + } + + void ensure_string_equals(const std::string& msg, const std::string& expected, const std::string& actual) + { + if ( expected != actual ) + { + std::string message = msg; + message += ": actual: "; + message += actual; + message += "\n expected: "; + message += expected; + message += "\n"; + ensure(message, false); + } + } + + void set_whitelist(LLMediaEntry &entry, const char *str) + { + std::vector tokens; + LLStringUtil::getTokens(std::string(str), tokens, ","); + entry.setWhiteList(tokens); + } + + void whitelist_test(bool enable, const char *whitelist, const char *candidate_url, bool expected_pass) + { + std::string message = "Whitelist test"; + LLMediaEntry entry; + entry.setWhiteListEnable(enable); + set_whitelist(entry, whitelist); + bool passed_whitelist = entry.checkCandidateUrl(candidate_url); + if (passed_whitelist != expected_pass) + { + message += " failed: expected "; + message += (expected_pass) ? "" : "NOT "; + message += "to match\nwhitelist = "; + message += whitelist; + message += "\ncandidate_url = "; + message += candidate_url; + } + ensure(message, expected_pass == passed_whitelist); + } + + void whitelist_test(const char *whitelist, const char *candidate_url, bool expected_pass) + { + whitelist_test(true, whitelist, candidate_url, expected_pass); + } + void whitelist_test(const char *whitelist, const char *candidate_url) + { + whitelist_test(true, whitelist, candidate_url, true); + } + + template<> template<> + void object::test<1>() + { + set_test_name("Test LLMediaEntry Instantiation"); + LLMediaEntry entry; + ensure_llsd_equals(get_test_name(), defaultMediaEntryLLSD, entry.asLLSD()); + + } + + template<> template<> + void object::test<2>() + { + set_test_name("Test LLMediaEntry Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + entry.fromLLSD(sd); + ensure_llsd_equals(get_test_name() + " failed", emptyMediaEntryLLSD, entry.asLLSD()); + } + + template<> template<> + void object::test<3>() + { + set_test_name("Test LLMediaEntry Partial Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; + entry.fromLLSD(sd); + LLSD golden; + std::istringstream p(PARTIAL_MEDIA_ENTRY("http://www.example.com")); + LLSDSerialize::fromXML(golden,p); + ensure_llsd_equals(get_test_name() + " failed", golden, entry.asLLSD()); + } + + // limit tests + const char *URL_OK = "http://www.example.com"; + const char *URL_TOO_BIG = "http://www.example.com.qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + + template<> template<> + void object::test<4>() + { + set_test_name("Test Limits on setting current URL"); + LLMediaEntry entry; + U32 status = entry.setCurrentURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setCurrentURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<5>() + { + set_test_name("Test Limits on setting home URL"); + LLMediaEntry entry; + U32 status = entry.setHomeURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setHomeURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<6>() + { + set_test_name("Test Limits on setting whitelist"); + + // Test a valid list + LLMediaEntry entry; + std::vector whitelist; + whitelist.push_back(std::string(URL_OK)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_OK); + ensure(get_test_name() + " failed", whitelist == entry.getWhiteList()); + } + + template<> template<> + void object::test<7>() + { + set_test_name("Test Limits on setting whitelist too big"); + + // Test an invalid list + LLMediaEntry entry; + std::vector whitelist, empty; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<8>() + { + set_test_name("Test Limits on setting whitelist too many"); + + // Test an invalid list + LLMediaEntry entry; + std::vector whitelist, empty; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + } + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<9>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test a valid list + std::vector whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_OK)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_OK && + entry2.setWhiteList(whitelist_llsd)== LSL_STATUS_OK ); + ensure(get_test_name() + " failed", + entry1.getWhiteList() == entry2.getWhiteList()); + } + + template<> template<> + void object::test<10>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list + std::vector whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + whitelist_llsd.append(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_TOO_BIG)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + template<> template<> + void object::test<11>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list, too many + std::vector whitelist, empty; + LLSD whitelist_llsd; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + whitelist_llsd.append("Q"); + } + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " invalid result", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + // Whitelist check tests + + // Check the "empty whitelist" case + template<> template<> + void object::test<12>() { whitelist_test("", "http://www.example.com", true); } + + // Check the "missing scheme" case + template<> template<> + void object::test<13>() { whitelist_test("www.example.com", "http://www.example.com", true); } + + // Check the "exactly the same" case + template<> template<> + void object::test<14>() { whitelist_test("http://example.com", "http://example.com", true); } + + // Check the enable flag + template<> template<> + void object::test<15>() { whitelist_test(false, "www.example.com", "http://www.secondlife.com", true); } + template<> template<> + void object::test<16>() { whitelist_test(true, "www.example.com", "http://www.secondlife.com", false); } + + // Check permutations of trailing slash: + template<> template<> + void object::test<17>() { whitelist_test("http://www.example.com", "http://www.example.com/", true); } + template<> template<> + void object::test<18>() { whitelist_test("http://www.example.com/", "http://www.example.com/", true); } + template<> template<> + void object::test<19>() { whitelist_test("http://www.example.com/", "http://www.example.com", false); } + template<> template<> + void object::test<20>() { whitelist_test("http://www.example.com", "http://www.example.com/foobar", true); } + template<> template<> + void object::test<21>() { whitelist_test("http://www.example.com/", "http://www.example.com/foobar", false); } + + + // More cases... + template<> template<> + void object::test<22>() { whitelist_test("http://example.com", "http://example.com/wiki", true); } + template<> template<> + void object::test<23>() { whitelist_test("www.example.com", "http://www.example.com/help", true); } + template<> template<> + void object::test<24>() { whitelist_test("http://www.example.com", "http://wwwexample.com", false); } + template<> template<> + void object::test<25>() { whitelist_test("http://www.example.com", "http://www.example.com/wiki", true); } + template<> template<> + void object::test<26>() { whitelist_test("example.com", "http://wwwexample.com", false); } + template<> template<> + void object::test<27>() { whitelist_test("http://www.example.com/", "http://www.amazon.com/wiki", false); } + template<> template<> + void object::test<28>() { whitelist_test("www.example.com", "http://www.amazon.com", false); } + + // regexp cases + template<> template<> + void object::test<29>() { whitelist_test("*.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<30>() { whitelist_test("*.example.com", "http://www.amazon.com", false); } + template<> template<> + void object::test<31>() { whitelist_test("*.example.com", "http://www.example.com/foo/bar", true); } + template<> template<> + void object::test<32>() { whitelist_test("*.example.com", "http:/example.com/foo/bar", false); } + template<> template<> + void object::test<33>() { whitelist_test("*example.com", "http://example.com/foo/bar", true); } + template<> template<> + void object::test<34>() { whitelist_test("*example.com", "http://my.virus.com/foo/bar?example.com", false); } + template<> template<> + void object::test<35>() { whitelist_test("example.com", "http://my.virus.com/foo/bar?example.com", false); } + template<> template<> + void object::test<36>() { whitelist_test("*example.com", "http://my.virus.com/foo/bar?*example.com", false); } + template<> template<> + void object::test<37>() { whitelist_test("http://*example.com", "http://www.example.com", true); } + template<> template<> + void object::test<38>() { whitelist_test("http://*.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<39>() { whitelist_test("http://*.e$?^.com", "http://www.e$?^.com", true); } + template<> template<> + void object::test<40>() { whitelist_test("*.example.com/foo/bar", "http://www.example.com/", false); } + template<> template<> + void object::test<41>() { whitelist_test("*.example.com/foo/bar", "http://example.com/foo/bar", false); } + template<> template<> + void object::test<42>() { whitelist_test("http://*.example.com/foo/bar", "http://www.example.com", false); } + template<> template<> + void object::test<43>() { whitelist_test("http://*.example.com", "https://www.example.com", false); } + template<> template<> + void object::test<44>() { whitelist_test("http*://*.example.com", "rtsp://www.example.com", false); } + template<> template<> + void object::test<45>() { whitelist_test("http*://*.example.com", "https://www.example.com", true); } + template<> template<> + void object::test<46>() { whitelist_test("example.com", "http://www.example.com", false); } + template<> template<> + void object::test<47>() { whitelist_test("www.example.com", "http://www.example.com:80", false); } + template<> template<> + void object::test<48>() { whitelist_test("www.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<49>() { whitelist_test("www.example.com/", "http://www.example.com", false); } + template<> template<> + void object::test<50>() { whitelist_test("www.example.com/foo/bar/*", "http://www.example.com/foo/bar/baz", true); } + // Path only + template<> template<> + void object::test<51>() { whitelist_test("/foo/*/baz", "http://www.example.com/foo/bar/baz", true); } + template<> template<> + void object::test<52>() { whitelist_test("/foo/*/baz", "http://www.example.com/foo/bar/", false); } +} diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 24efcb8ae8..7a531e0fbf 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -383,7 +383,7 @@ BOOL LLDir_Linux::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLPlugin"; } diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 9be787df11..346f7dd8ed 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -424,7 +424,7 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Mac::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() + "SLPlugin"; } diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 872f2cf1c1..3e302764de 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -397,7 +397,7 @@ BOOL LLDir_Win32::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Win32::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLPlugin.exe"; } diff --git a/indra/lscript/lscript_compile/CMakeLists.txt b/indra/lscript/lscript_compile/CMakeLists.txt index 252085bab2..3ed2892e0e 100644 --- a/indra/lscript/lscript_compile/CMakeLists.txt +++ b/indra/lscript/lscript_compile/CMakeLists.txt @@ -5,6 +5,7 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLInventory) +include(LLPrimitive) include(LScript) include(FindCygwin) @@ -41,6 +42,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} + ${LLPRIMITIVE_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ) diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index 9cc2841e8c..8c891b3e8f 100644 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -34,6 +34,7 @@ FS (f|F) #include "llregionflags.h" #include "lscript_http.h" #include "llclickaction.h" +#include "llmediaentry.h" void count(); void line_comment(); @@ -233,7 +234,8 @@ extern "C" { int yyerror(const char *fmt, ...); } "CHANGED_OWNER" { count(); yylval.ival = CHANGED_OWNER; return(INTEGER_CONSTANT); } "CHANGED_REGION" { count(); yylval.ival = CHANGED_REGION; return(INTEGER_CONSTANT); } "CHANGED_TELEPORT" { count(); yylval.ival = CHANGED_TELEPORT; return(INTEGER_CONSTANT); } -"CHANGED_REGION_START" { count(); yylval.ival = CHANGED_REGION_START; return(INTEGER_CONSTANT); } +"CHANGED_REGION_START" { count(); yylval.ival = CHANGED_REGION_START; return(INTEGER_CONSTANT); } +"CHANGED_MEDIA" { count(); yylval.ival = CHANGED_MEDIA; return(INTEGER_CONSTANT); } "OBJECT_UNKNOWN_DETAIL" { count(); yylval.ival = OBJECT_UNKNOWN_DETAIL; return(INTEGER_CONSTANT); } "OBJECT_NAME" { count(); yylval.ival = OBJECT_NAME; return(INTEGER_CONSTANT); } @@ -622,6 +624,45 @@ extern "C" { int yyerror(const char *fmt, ...); } "TOUCH_INVALID_VECTOR" { count(); return(TOUCH_INVALID_VECTOR); } "TOUCH_INVALID_TEXCOORD" { count(); return(TOUCH_INVALID_TEXCOORD); } +"PRIM_MEDIA_ALT_IMAGE_ENABLE" { count(); yylval.ival = LLMediaEntry::ALT_IMAGE_ENABLE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CONTROLS" { count(); yylval.ival = LLMediaEntry::CONTROLS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CURRENT_URL" { count(); yylval.ival = LLMediaEntry::CURRENT_URL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_HOME_URL" { count(); yylval.ival = LLMediaEntry::HOME_URL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_LOOP" { count(); yylval.ival = LLMediaEntry::AUTO_LOOP_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_PLAY" { count(); yylval.ival = LLMediaEntry::AUTO_PLAY_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_SCALE" { count(); yylval.ival = LLMediaEntry::AUTO_SCALE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_ZOOM" { count(); yylval.ival = LLMediaEntry::AUTO_ZOOM_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_FIRST_CLICK_INTERACT" { count(); yylval.ival = LLMediaEntry::FIRST_CLICK_INTERACT_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WIDTH_PIXELS" { count(); yylval.ival = LLMediaEntry::WIDTH_PIXELS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_HEIGHT_PIXELS" { count(); yylval.ival = LLMediaEntry::HEIGHT_PIXELS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WHITELIST_ENABLE" { count(); yylval.ival = LLMediaEntry::WHITELIST_ENABLE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WHITELIST" { count(); yylval.ival = LLMediaEntry::WHITELIST_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERMS_INTERACT" { count(); yylval.ival = LLMediaEntry::PERMS_INTERACT_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERMS_CONTROL" { count(); yylval.ival = LLMediaEntry::PERMS_CONTROL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PARAM_MAX" { count(); yylval.ival = LLMediaEntry::PARAM_MAX_ID; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_CONTROLS_STANDARD" { count(); yylval.ival = LLMediaEntry::STANDARD; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CONTROLS_MINI" { count(); yylval.ival = LLMediaEntry::MINI; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_PERM_NONE" { count(); yylval.ival = LLMediaEntry::PERM_NONE; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_OWNER" { count(); yylval.ival = LLMediaEntry::PERM_OWNER; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_GROUP" { count(); yylval.ival = LLMediaEntry::PERM_GROUP; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_ANYONE" { count(); yylval.ival = LLMediaEntry::PERM_ANYONE; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_MAX_URL_LENGTH" { count(); yylval.ival = LLMediaEntry::MAX_URL_LENGTH; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WHITELIST_SIZE" { count(); yylval.ival = LLMediaEntry::MAX_WHITELIST_SIZE; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WHITELIST_COUNT" { count(); yylval.ival = LLMediaEntry::MAX_WHITELIST_COUNT; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WIDTH_PIXELS" { count(); yylval.ival = LLMediaEntry::MAX_WIDTH_PIXELS; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_HEIGHT_PIXELS" { count(); yylval.ival = LLMediaEntry::MAX_HEIGHT_PIXELS; return(INTEGER_CONSTANT); } + +"STATUS_OK" { count(); yylval.ival = LSL_STATUS_OK; return(INTEGER_CONSTANT); } +"STATUS_MALFORMED_PARAMS" { count(); yylval.ival = LSL_STATUS_MALFORMED_PARAMS; return(INTEGER_CONSTANT); } +"STATUS_TYPE_MISMATCH" { count(); yylval.ival = LSL_STATUS_TYPE_MISMATCH; return(INTEGER_CONSTANT); } +"STATUS_BOUNDS_ERROR" { count(); yylval.ival = LSL_STATUS_BOUNDS_ERROR; return(INTEGER_CONSTANT); } +"STATUS_NOT_FOUND" { count(); yylval.ival = LSL_STATUS_NOT_FOUND; return(INTEGER_CONSTANT); } +"STATUS_NOT_SUPPORTED" { count(); yylval.ival = LSL_STATUS_NOT_SUPPORTED; return(INTEGER_CONSTANT); } +"STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); } +"STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); } {L}({L}|{N})* { count(); yylval.sval = new char[strlen(yytext) + 1]; strcpy(yylval.sval, yytext); return(IDENTIFIER); } diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index 0d51c27c92..5e394644c2 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -450,7 +450,12 @@ void LLScriptLibrary::init() addFunction(10.f, 0.f, dummy_func, "llHTTPResponse", NULL, "kis"); addFunction(10.f, 0.f, dummy_func, "llGetHTTPHeader", "s", "ks"); - // energy, sleep, dummy_func, name, return type, parameters, gods-only + // Prim media (see lscript_prim_media.h) + addFunction(10.f, 1.0f, dummy_func, "llSetPrimMediaParams", "i", "il"); + addFunction(10.f, 1.0f, dummy_func, "llGetPrimMediaParams", "l", "il"); + addFunction(10.f, 1.0f, dummy_func, "llClearPrimMedia", "i", "i"); + + // energy, sleep, dummy_func, name, return type, parameters, help text, gods-only // IF YOU ADD NEW SCRIPT CALLS, YOU MUST PUT THEM AT THE END OF THIS LIST. // Otherwise the bytecode numbers for each call will be wrong, and all @@ -495,7 +500,7 @@ void LLScriptLibData::print(std::ostream &s, BOOL b_prepend_comma) s << ", "; } switch (mType) - { + { case LST_INTEGER: s << mInteger; break; diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp index 647db7a5bf..a4c43988ba 100644 --- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -975,10 +975,7 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index e9be458960..fbda65120d 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -772,10 +772,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 2928b7e6b3..eb2457744a 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -147,8 +147,11 @@ private: #if LL_WINDOWS // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#else + LLQtWebKit::getInstance()->enablePlugins(false); +#elif LL_DARWIN + // Disable plugins + LLQtWebKit::getInstance()->enablePlugins(false); +#elif LL_LINUX // Disable plugins LLQtWebKit::getInstance()->enablePlugins(false); #endif @@ -164,6 +167,11 @@ private: // don't flip bitmap LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); + + // Set the background color to black + LLQtWebKit::getInstance()-> + // set background color to be black - mostly for initial login page + LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 ); // go to the "home page" // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. @@ -483,8 +491,8 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) mDepth = 4; message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 800); - message.setValueS32("default_height", 600); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); message.setValueS32("depth", mDepth); message.setValueU32("internalformat", GL_RGBA); message.setValueU32("format", GL_RGBA); @@ -507,10 +515,7 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b74f67e72e..b217a5b781 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -171,6 +171,7 @@ set(viewer_SOURCE_FILES llfloaterhardwaresettings.cpp llfloaterhelpbrowser.cpp llfloatermediabrowser.cpp + llfloatermediasettings.cpp llfloaterhud.cpp llfloaterimagepreview.cpp llfloaterinspect.cpp @@ -207,6 +208,7 @@ set(viewer_SOURCE_FILES llfloaterurlentry.cpp llfloatervoicedevicesettings.cpp llfloaterwater.cpp + llfloaterwhitelistentry.cpp llfloaterwindlight.cpp llfloaterworldmap.cpp llfoldertype.cpp @@ -259,6 +261,9 @@ set(viewer_SOURCE_FILES llmanipscale.cpp llmaniptranslate.cpp llmapresponders.cpp + llmediactrl.cpp + llmediadataresponder.cpp + llmediadatafetcher.cpp llmediaremotectrl.cpp llmemoryview.cpp llmenucommands.cpp @@ -320,6 +325,9 @@ set(viewer_SOURCE_FILES llpanelmediahud.cpp llpanelmeprofile.cpp llpanelmovetip.cpp + llpanelmediasettingsgeneral.cpp + llpanelmediasettingssecurity.cpp + llpanelmediasettingspermissions.cpp llpanelobject.cpp llpanelpeople.cpp llpanelpeoplemenus.cpp @@ -491,7 +499,6 @@ set(viewer_SOURCE_FILES llwearabledictionary.cpp llwearablelist.cpp llweb.cpp - llmediactrl.cpp llwind.cpp llwlanimator.cpp llwldaycycle.cpp @@ -635,6 +642,7 @@ set(viewer_HEADER_FILES llfloaterhardwaresettings.h llfloaterhelpbrowser.h llfloatermediabrowser.h + llfloatermediasettings.h llfloaterhud.h llfloaterimagepreview.h llfloaterinspect.h @@ -671,6 +679,7 @@ set(viewer_HEADER_FILES llfloaterurlentry.h llfloatervoicedevicesettings.h llfloaterwater.h + llfloaterwhitelistentry.h llfloaterwindlight.h llfloaterworldmap.h llfoldertype.h @@ -723,6 +732,8 @@ set(viewer_HEADER_FILES llmanipscale.h llmaniptranslate.h llmapresponders.h + llmediadataresponder.h + llmediadatafetcher.h llmediaremotectrl.h llmemoryview.h llmenucommands.h @@ -781,6 +792,9 @@ set(viewer_HEADER_FILES llpanelmediahud.h llpanelmeprofile.h llpanelmovetip.h + llpanelmediasettingsgeneral.h + llpanelmediasettingssecurity.h + llpanelmediasettingspermissions.h llpanelobject.h llpanelpeople.h llpanelpeoplemenus.h @@ -1566,7 +1580,7 @@ if (WINDOWS) -E copy_if_different ${BUILT_SLPLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} COMMENT "Copying SLPlugin executable to the runtime folder." ) diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index a6abde36e3..5d52158298 100644 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -47,7 +47,7 @@ moving_end moving_end():Triggered when task stops moving on_rez on_rez(integer start_param):Triggered when task is rezed in from inventory or another task object_rez object_rez(key id):Triggered when task rezes in another task link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call -changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT) +changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL @@ -320,6 +320,7 @@ CHANGED_OWNER Parameter of changed event handler used to indicate change to tas CHANGED_REGION Parameter of changed event handler used to indicate the region has changed CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted +CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task TYPE_INTEGER Indicates that the list entry is holding an integer TYPE_FLOAT Indicates that the list entry is holding an float @@ -513,6 +514,46 @@ TOUCH_INVALID_TEXCOORD Value returned by llDetectedTouchUV() and llDetectedTouc TOUCH_INVALID_VECTOR Value returned by llDetectedTouchPos(), llDetectedTouchNormal(), and llDetectedTouchBinormal() when the touch position is not valid. TOUCH_INVALID_FACE Value returned by llDetectedTouchFace() when the touch position is not valid. +PRIM_MEDIA_ALT_IMAGE_ENABLE Used with ll{Get,Set}PrimMediaParams to enable the default alt image for media +PRIM_MEDIA_CONTROLS Used with ll{Get,Set}PrimMediaParams to determine the controls shown for media +PRIM_MEDIA_CURRENT_URL Used with ll{Get,Set}PrimMediaParams to navigate/access the current URL +PRIM_MEDIA_HOME_URL Used with ll{Get,Set}PrimMediaParams to access the home URL +PRIM_MEDIA_AUTO_LOOP Used with ll{Get,Set}PrimMediaParams to determine if media should auto-loop (if applicable) +PRIM_MEDIA_AUTO_PLAY Used with ll{Get,Set}PrimMediaParams to determine if media should start playing as soon as it is created +PRIM_MEDIA_AUTO_SCALE Used with ll{Get,Set}PrimMediaParams to determine if media should scale to fit the face it is on +PRIM_MEDIA_AUTO_ZOOM Used with ll{Get,Set}PrimMediaParams to determine if the user would zoom in when viewing media +PRIM_MEDIA_FIRST_CLICK_INTERACT Used with ll{Get,Set}PrimMediaParams to determine whether the user interacts with media or not when she first clicks it (versus selection) +PRIM_MEDIA_WIDTH_PIXELS Used with ll{Get,Set}PrimMediaParams to access the media's width in pixels +PRIM_MEDIA_HEIGHT_PIXELS Used with ll{Get,Set}PrimMediaParams to access the media's height in pixels +PRIM_MEDIA_WHITELIST_ENABLE Used with ll{Get,Set}PrimMediaParams to determine if the domain whitelist is enabled +PRIM_MEDIA_WHITELIST Used with ll{Get,Set}PrimMediaParams to access the media's list of allowable URL prefixes to navigate to +PRIM_MEDIA_PERMS_INTERACT Used with ll{Get,Set}PrimMediaParams to determine the permissions for who can interact with the media +PRIM_MEDIA_PERMS_CONTROL Used with ll{Get,Set}PrimMediaParams to determine the permissions for who has controls +PRIM_MEDIA_PARAM_MAX The value of the largest media param + +PRIM_MEDIA_CONTROLS_STANDARD Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_CONTROLS value meaning "standard controls" +PRIM_MEDIA_CONTROLS_MINI Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_CONTROLS value meaning "mini controls" + +PRIM_MEDIA_PERM_NONE Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, no permissions +PRIM_MEDIA_PERM_OWNER Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, owner permissions +PRIM_MEDIA_PERM_GROUP Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, group permissions +PRIM_MEDIA_PERM_ANYONE Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, anyone has permissions + +PRIM_MEDIA_MAX_URL_LENGTH Used with ll{Get,Set}PrimMediaParams, the maximum length of PRIM_MEDIA_CURRENT_URL or PRIM_MEDIA_HOME_URL +PRIM_MEDIA_MAX_WHITELIST_SIZE Used with ll{Get,Set}PrimMediaParams, the maximum length, in bytes, of PRIM_MEDIA_WHITELIST +PRIM_MEDIA_MAX_WHITELIST_COUNT Used with ll{Get,Set}PrimMediaParams, the maximum number of items allowed in PRIM_MEDIA_WHITELIST +PRIM_MEDIA_MAX_WIDTH_PIXELS Used with ll{Get,Set}PrimMediaParams, the maximum width allowed in PRIM_MEDIA_WIDTH_PIXELS +PRIM_MEDIA_MAX_HEIGHT_PIXELS Used with ll{Get,Set}PrimMediaParams, the maximum width allowed in PRIM_MEDIA_HEIGHT_PIXELS + +STATUS_OK Result of function call was success +STATUS_MALFORMED_PARAMS Function was called with malformed params +STATUS_TYPE_MISMATCH Argument(s) passed to function had a type mismatch +STATUS_BOUNDS_ERROR Argument(s) passed to function had a bounds error +STATUS_NOT_FOUND Object or other item was not found +STATUS_NOT_SUPPORTED Feature not supported +STATUS_INTERNAL_ERROR An internal error occurred +STATUS_WHITELIST_FAILED URL failed to pass whitelist + # string constants [word .1, .3, .5] NULL_KEY Indicates an empty key diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8cbe6d20c6..99b662a63f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3994,6 +3994,17 @@ Value 0 + LastMediaSettingsTab + + Comment + Last selected tab in media settings window + Persist + 1 + Type + S32 + Value + 0 + LastRunVersion Comment @@ -4455,7 +4466,7 @@ Type Boolean Value - 0 + 1 MemoryLogFrequency @@ -5216,6 +5227,51 @@ Value 1 + + PluginInstancesCPULimit + + Comment + Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check. + Persist + 1 + Type + F32 + Value + 0.0 + + PluginInstancesLow + + Comment + Limit on the number of inworld media plugins that will run at "low" priority + Persist + 1 + Type + U32 + Value + 4 + + PluginInstancesNormal + + Comment + Limit on the number of inworld media plugins that will run at "normal" priority + Persist + 1 + Type + U32 + Value + 4 + + PluginInstancesTotal + + Comment + Hard limit on the number of plugins that will be instantiated at once + Persist + 1 + Type + U32 + Value + 16 + PrecachingDelay Comment @@ -5238,6 +5294,28 @@ Value 13 + PrimMediaFetchQueueDelay + + Comment + Timer delay for fetching media from the queue (in seconds). + Persist + 1 + Type + F32 + Value + 1.0 + + PrimMediaRetryTimerDelay + + Comment + Timer delay for retrying on media queries (in seconds). + Persist + 1 + Type + F32 + Value + 5.0 + ProbeHardwareOnStartup Comment diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4cf12a1533..069155c255 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -960,6 +960,30 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() return retval; } +const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. +//static +S32 LLDrawable::getMinVisFrameRange() +{ + return MIN_VIS_FRAME_RANGE ; +} + +BOOL LLDrawable::isRecentlyVisible() const +{ + //currently visible or visible in the previous frame. + BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE) ; + + if(!vis) + { + LLSpatialGroup* group = getSpatialGroup(); + if (group && group->isRecentlyVisible()) + { + mVisible = sCurVisible; + vis = TRUE ; + } + } + + return vis ; +} BOOL LLDrawable::isVisible() const { diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 986440397b..5a10b688da 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -78,7 +78,8 @@ public: BOOL isLight() const; - BOOL isVisible() const; + BOOL isVisible() const; + BOOL isRecentlyVisible() const; virtual void setVisible(LLCamera& camera_in, std::vector* results = NULL, BOOL for_select = FALSE); @@ -278,7 +279,8 @@ public: S32 mQuietCount; static S32 getCurrentFrame() { return sCurVisible; } - + static S32 getMinVisFrameRange(); + void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index fc5b27dd1b..a5b0b05603 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -270,16 +270,34 @@ void LLFace::setTexture(LLViewerTexture* tex) { mTexture->removeFace(this) ; removeAtlas() ; - } + } mTexture = tex ; - + if(mTexture.notNull()) { mTexture->addFace(this) ; } } +void LLFace::switchTexture(LLViewerTexture* new_texture) +{ + if(mTexture == new_texture) + { + return ; + } + + if(!new_texture) + { + llerrs << "Can not switch to a null texture." << llendl ; + } + new_texture->addTextureStats(mTexture->getMaxVirtualSize()) ; + + getViewerObject()->changeTEImage(mTEOffset, new_texture) ; + setTexture(new_texture) ; + gPipeline.markTextured(getDrawable()); +} + void LLFace::setTEOffset(const S32 te_offset) { mTEOffset = te_offset; diff --git a/indra/newview/llface.h b/indra/newview/llface.h index cafad5706c..f6ffefcb7c 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -89,6 +89,7 @@ public: U16 getGeomIndex() const { return mGeomIndex; } // index into draw pool U16 getGeomStart() const { return mGeomIndex; } // index into draw pool void setTexture(LLViewerTexture* tex) ; + void switchTexture(LLViewerTexture* new_texture); LLXformMatrix* getXform() const { return mXform; } BOOL hasGeometry() const { return mGeomCount > 0; } LLVector3 getPositionAgent() const; diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index c7ec4bd585..9b7f3305e5 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -146,7 +146,10 @@ void LLFloaterMediaBrowser::buildURLHistory() } // initialize URL history in the plugin - mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); + if(mBrowser && mBrowser->getMediaPlugin()) + { + mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); + } } std::string LLFloaterMediaBrowser::getSupportURL() diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp new file mode 100644 index 0000000000..811cc26efb --- /dev/null +++ b/indra/newview/llfloatermediasettings.cpp @@ -0,0 +1,249 @@ +/** + * @file llfloatermediasettings.cpp + * @brief Tabbed dialog for media settings - class implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" +#include "llfloatermediasettings.h" +#include "llpanelmediasettingsgeneral.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelmediasettingspermissions.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llselectmgr.h" + +LLFloaterMediaSettings* LLFloaterMediaSettings::sInstance = NULL; + +//////////////////////////////////////////////////////////////////////////////// +// +LLFloaterMediaSettings::LLFloaterMediaSettings(const LLSD& key) + : LLFloater(key), + mTabContainer(NULL), + mPanelMediaSettingsGeneral(NULL), + mPanelMediaSettingsSecurity(NULL), + mPanelMediaSettingsPermissions(NULL), + mWaitingToClose( false ) +{ +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_settings.xml"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLFloaterMediaSettings::~LLFloaterMediaSettings() +{ + if ( mPanelMediaSettingsGeneral ) + { + delete mPanelMediaSettingsGeneral; + mPanelMediaSettingsGeneral = NULL; + } + + if ( mPanelMediaSettingsSecurity ) + { + delete mPanelMediaSettingsSecurity; + mPanelMediaSettingsSecurity = NULL; + } + + if ( mPanelMediaSettingsPermissions ) + { + delete mPanelMediaSettingsPermissions; + mPanelMediaSettingsPermissions = NULL; + } + + sInstance = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLFloaterMediaSettings::postBuild() +{ + mCloseSignal.connect(boost::bind(&LLFloaterMediaSettings::onClose, this)); + + mApplyBtn = getChild("Apply"); + mApplyBtn->setClickedCallback(onBtnApply, this); + + mCancelBtn = getChild("Cancel"); + mCancelBtn->setClickedCallback(onBtnCancel, this); + + mOKBtn = getChild("OK"); + mOKBtn->setClickedCallback(onBtnOK, this); + + mTabContainer = getChild( "tab_container" ); + + mPanelMediaSettingsGeneral = new LLPanelMediaSettingsGeneral(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsGeneral)); + mPanelMediaSettingsGeneral->setParent( this ); + + // note that "permissions" tab is really "Controls" tab - refs to 'perms' and + // 'permissions' not changed to 'controls' since we don't want to change + // shared files in server code and keeping everything the same seemed best. + mPanelMediaSettingsPermissions = new LLPanelMediaSettingsPermissions(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsPermissions)); + + mPanelMediaSettingsSecurity = new LLPanelMediaSettingsSecurity(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsSecurity)); + + // restore the last tab viewed from persistance variable storage + if (!mTabContainer->selectTab(gSavedSettings.getS32("LastMediaSettingsTab"))) + { + mTabContainer->selectFirstTab(); + }; + + sInstance = this; + + return TRUE; +} + +//static +LLFloaterMediaSettings* LLFloaterMediaSettings::getInstance() +{ + if ( !sInstance ) + { + sInstance = (LLFloaterReg::getTypedInstance("media_settings")); + } + + return sInstance; +} + +//static +void LLFloaterMediaSettings::apply() +{ + + LLSD settings; + sInstance->mPanelMediaSettingsGeneral->getValues( settings ); + sInstance->mPanelMediaSettingsSecurity->getValues( settings ); + sInstance->mPanelMediaSettingsPermissions->getValues( settings ); + LLSelectMgr::getInstance()->selectionSetMedia( LLTextureEntry::MF_HAS_MEDIA ); + LLSelectMgr::getInstance()->selectionSetMediaData(settings); +} + +//////////////////////////////////////////////////////////////////////////////// +void LLFloaterMediaSettings::onClose() +{ + if(mPanelMediaSettingsGeneral) + { + mPanelMediaSettingsGeneral->onClose(); + } + LLFloaterReg::hideInstance("whitelist_entry"); +} + +//////////////////////////////////////////////////////////////////////////////// +//static +void LLFloaterMediaSettings::initValues( const LLSD& media_settings ) +{ + sInstance->clearValues(); + // update all panels with values from simulator + sInstance->mPanelMediaSettingsGeneral-> + initValues( sInstance->mPanelMediaSettingsGeneral, media_settings ); + + sInstance->mPanelMediaSettingsSecurity-> + initValues( sInstance->mPanelMediaSettingsSecurity, media_settings ); + + sInstance->mPanelMediaSettingsPermissions-> + initValues( sInstance->mPanelMediaSettingsPermissions, media_settings ); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterMediaSettings::commitFields() +{ + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +//static +void LLFloaterMediaSettings::clearValues() +{ + // clean up all panels before updating + sInstance->mPanelMediaSettingsGeneral->clearValues(sInstance->mPanelMediaSettingsGeneral); + sInstance->mPanelMediaSettingsSecurity->clearValues(sInstance->mPanelMediaSettingsSecurity); + sInstance->mPanelMediaSettingsPermissions->clearValues(sInstance->mPanelMediaSettingsPermissions); +} + + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnOK( void* userdata ) +{ + sInstance->commitFields(); + + sInstance->apply(); + + sInstance->closeFloater(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnApply( void* userdata ) +{ + sInstance->commitFields(); + + sInstance->apply(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnCancel( void* userdata ) +{ + sInstance->closeFloater(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onTabChanged(void* user_data, bool from_click) +{ + LLTabContainer* self = (LLTabContainer*)user_data; + gSavedSettings.setS32("LastMediaSettingsTab", self->getCurrentPanelIndex()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterMediaSettings::enableOkApplyBtns( bool enable ) +{ + setCtrlsEnabled( enable ); + childSetEnabled( "OK", enable ); + childSetEnabled( "Apply", enable ); +} diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h new file mode 100644 index 0000000000..b95c590346 --- /dev/null +++ b/indra/newview/llfloatermediasettings.h @@ -0,0 +1,81 @@ +/** + * @file llfloatermediasettings.cpp + * @brief Tabbed dialog for media settings - class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMEDIASETTINGS_H +#define LL_LLFLOATERMEDIASETTINGS_H + +#include "llfloater.h" +#include "lltabcontainer.h" + +class LLPanelMediaSettingsGeneral; +class LLPanelMediaSettingsSecurity; +class LLPanelMediaSettingsPermissions; + +class LLFloaterMediaSettings : + public LLFloater +{ +public: + LLFloaterMediaSettings(const LLSD& key); + ~LLFloaterMediaSettings(); + + virtual BOOL postBuild(); + static LLFloaterMediaSettings* getInstance(); + static void apply(); + static void initValues( const LLSD& media_settings ); + static void clearValues(); + void enableOkApplyBtns( bool enable ); + LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;}; + +protected: + LLButton *mOKBtn; + LLButton *mCancelBtn; + LLButton *mApplyBtn; + + LLTabContainer *mTabContainer; + LLPanelMediaSettingsGeneral* mPanelMediaSettingsGeneral; + LLPanelMediaSettingsSecurity* mPanelMediaSettingsSecurity; + LLPanelMediaSettingsPermissions* mPanelMediaSettingsPermissions; + + void onClose(); + static void onBtnOK(void*); + static void onBtnCancel(void*); + static void onBtnApply(void*); + static void onTabChanged(void* user_data, bool from_click); + void commitFields(); + + static LLFloaterMediaSettings* sInstance; + +private: + bool mWaitingToClose; +}; + +#endif // LL_LLFLOATERMEDIASETTINGS_H diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 761b5c9219..57c043a1e0 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -195,8 +195,8 @@ void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); viewer_media_t get_web_media() { - viewer_media_t media_source = LLViewerMedia::newMediaImpl("", LLUUID::null, 0, 0, 0, 0, "text/html"); - + viewer_media_t media_source = LLViewerMedia::newMediaImpl(LLUUID::null); + media_source->initializeMedia("text/html"); return media_source; } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index f334344279..7dc29379e4 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -44,9 +44,11 @@ #include "llcombobox.h" #include "lldraghandle.h" #include "llfloaterbuildoptions.h" +#include "llfloatermediasettings.h" #include "llfloateropenobject.h" #include "llfloaterreg.h" #include "llfocusmgr.h" +#include "llmediaentry.h" #include "llmenugl.h" #include "llpanelcontents.h" #include "llpanelface.h" @@ -97,7 +99,7 @@ const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] = }; // Local prototypes -void commit_select_component(LLUICtrl *ctrl, void *data); +void commit_select_component(void *data); void click_show_more(void*); void click_popup_info(void*); void click_popup_done(void*); @@ -105,15 +107,14 @@ void click_popup_minimize(void*); void click_popup_rotate_left(void*); void click_popup_rotate_reset(void*); void click_popup_rotate_right(void*); -void commit_slider_dozer_size(LLUICtrl *, void*); -void commit_slider_dozer_force(LLUICtrl *, void*); +void commit_slider_dozer_force(LLUICtrl *); void click_apply_to_selection(void*); -void commit_radio_group_focus(LLUICtrl* ctrl, void* data); -void commit_radio_group_move(LLUICtrl* ctrl, void* data); -void commit_radio_group_edit(LLUICtrl* ctrl, void* data); -void commit_radio_group_land(LLUICtrl* ctrl, void* data); -void commit_grid_mode(LLUICtrl *, void*); -void commit_slider_zoom(LLUICtrl *, void*); +void commit_radio_group_focus(LLUICtrl* ctrl); +void commit_radio_group_move(LLUICtrl* ctrl); +void commit_radio_group_edit(LLUICtrl* ctrl); +void commit_radio_group_land(LLUICtrl* ctrl); +void commit_grid_mode(LLUICtrl *); +void commit_slider_zoom(LLUICtrl *ctrl); //static @@ -210,43 +211,28 @@ BOOL LLFloaterTools::postBuild() getDragHandle()->setEnabled( !gSavedSettings.getBOOL("ToolboxAutoMove") ); LLRect rect; - mBtnFocus = getChild("button focus");//btn; - childSetAction("button focus",LLFloaterTools::setEditTool, (void*)LLToolCamera::getInstance()); - mBtnMove = getChild("button move"); - childSetAction("button move",LLFloaterTools::setEditTool, (void*)LLToolGrab::getInstance()); - mBtnEdit = getChild("button edit"); - childSetAction("button edit",LLFloaterTools::setEditTool, (void*)LLToolCompTranslate::getInstance()); - mBtnCreate = getChild("button create"); - childSetAction("button create",LLFloaterTools::setEditTool, (void*)LLToolCompCreate::getInstance()); - mBtnLand = getChild("button land" ); - childSetAction("button land",LLFloaterTools::setEditTool, (void*)LLToolSelectLand::getInstance()); - mTextStatus = getChild("text status"); - - childSetCommitCallback("slider zoom",commit_slider_zoom,this); - - mRadioGroupFocus = getChild("focus_radio_group"); - childSetCommitCallback("focus_radio_group", commit_radio_group_focus, this); - - mRadioGroupMove = getChild("move_radio_group"); - childSetCommitCallback("move_radio_group", commit_radio_group_move, this); - - mRadioGroupEdit = getChild("edit_radio_group"); - childSetCommitCallback("edit_radio_group", commit_radio_group_edit, this); - - mCheckSelectIndividual = getChild("checkbox edit linked parts"); + mBtnFocus = getChild("button focus");//btn; + mBtnMove = getChild("button move"); + mBtnEdit = getChild("button edit"); + mBtnCreate = getChild("button create"); + mBtnLand = getChild("button land" ); + mTextStatus = getChild("text status"); + mRadioGroupFocus = getChild("focus_radio_group"); + mRadioGroupMove = getChild("move_radio_group"); + mRadioGroupEdit = getChild("edit_radio_group"); + mBtnGridOptions = getChild("Options..."); + + mCheckSelectIndividual = getChild("checkbox edit linked parts"); childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts")); - childSetCommitCallback("checkbox edit linked parts",commit_select_component,this); - mCheckSnapToGrid = getChild("checkbox snap to grid"); + mCheckSnapToGrid = getChild("checkbox snap to grid"); childSetValue("checkbox snap to grid",(BOOL)gSavedSettings.getBOOL("SnapEnabled")); - mBtnGridOptions = getChild("Options..."); - childSetAction("Options...",onClickGridOptions, this); - mCheckStretchUniform = getChild("checkbox uniform"); + mCheckStretchUniform = getChild("checkbox uniform"); childSetValue("checkbox uniform",(BOOL)gSavedSettings.getBOOL("ScaleUniform")); - mCheckStretchTexture = getChild("checkbox stretch textures"); + mCheckStretchTexture = getChild("checkbox stretch textures"); childSetValue("checkbox stretch textures",(BOOL)gSavedSettings.getBOOL("ScaleStretchTextures")); - mTextGridMode = getChild("text ruler mode"); - mComboGridMode = getChild("combobox grid mode"); - childSetCommitCallback("combobox grid mode",commit_grid_mode, this); + mTextGridMode = getChild("text ruler mode"); + mComboGridMode = getChild("combobox grid mode"); + // // Create Buttons // @@ -271,18 +257,11 @@ BOOL LLFloaterTools::postBuild() mCheckCopyRotates = getChild("checkbox copy rotates"); childSetValue("checkbox copy rotates",(BOOL)gSavedSettings.getBOOL("CreateToolCopyRotates")); - mRadioGroupLand = getChild("land_radio_group"); - childSetCommitCallback("land_radio_group", commit_radio_group_land, this); - - mBtnApplyToSelection = getChild("button apply to selection"); - childSetAction("button apply to selection",click_apply_to_selection, (void*)0); - - mSliderDozerSize = getChild("slider brush size"); - childSetCommitCallback("slider brush size", commit_slider_dozer_size, (void*)0); + mRadioGroupLand = getChild("land_radio_group"); + mBtnApplyToSelection = getChild("button apply to selection"); + mSliderDozerSize = getChild("slider brush size"); childSetValue( "slider brush size", gSavedSettings.getF32("LandBrushSize")); - - mSliderDozerForce = getChild("slider force"); - childSetCommitCallback("slider force",commit_slider_dozer_force, (void*)0); + mSliderDozerForce = getChild("slider force"); // the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here childSetValue( "slider force", log10(gSavedSettings.getF32("LandBrushForce"))); @@ -369,6 +348,22 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_tools.xml",FALSE); + mCommitCallbackRegistrar.add("BuildTool.setTool", boost::bind(&LLFloaterTools::setTool,this, _2)); + mCommitCallbackRegistrar.add("BuildTool.commitZoom", boost::bind(&commit_slider_zoom, _1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", boost::bind(&commit_radio_group_focus, _1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", boost::bind(&commit_radio_group_move,_1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1)); + + mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this)); + mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this)); + mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this)); + mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1)); + mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", boost::bind(&commit_slider_dozer_force,_1)); + mCommitCallbackRegistrar.add("BuildTool.AddMedia", boost::bind(&LLFloaterTools::onClickBtnAddMedia,this)); + mCommitCallbackRegistrar.add("BuildTool.DeleteMedia", boost::bind(&LLFloaterTools::onClickBtnDeleteMedia,this)); + mCommitCallbackRegistrar.add("BuildTool.EditMedia", boost::bind(&LLFloaterTools::onClickBtnEditMedia,this)); + } LLFloaterTools::~LLFloaterTools() @@ -427,6 +422,7 @@ void LLFloaterTools::refresh() mPanelObject->refresh(); mPanelVolume->refresh(); mPanelFace->refresh(); + refreshMedia(); mPanelContents->refresh(); mPanelLandInfo->refresh(); } @@ -756,6 +752,7 @@ void LLFloaterTools::onClose() LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool(); //gMenuBarView->setItemVisible("BuildTools", FALSE); + LLFloaterReg::hideInstance("media_settings"); } void click_popup_info(void*) @@ -767,7 +764,7 @@ void click_popup_done(void*) handle_reset_view(); } -void commit_radio_group_move(LLUICtrl* ctrl, void* data) +void commit_radio_group_move(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -788,7 +785,7 @@ void commit_radio_group_move(LLUICtrl* ctrl, void* data) } } -void commit_radio_group_focus(LLUICtrl* ctrl, void* data) +void commit_radio_group_focus(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -812,7 +809,7 @@ void commit_radio_group_focus(LLUICtrl* ctrl, void* data) } } -void commit_slider_zoom(LLUICtrl *ctrl, void*) +void commit_slider_zoom(LLUICtrl *ctrl) { // renormalize value, since max "volume" level is 0.5 for some reason F32 zoom_level = (F32)ctrl->getValue().asReal() * 2.f; // / 0.5f; @@ -837,26 +834,19 @@ void click_popup_rotate_right(void*) dialog_refresh_all(); } - -void commit_slider_dozer_size(LLUICtrl *ctrl, void*) -{ - F32 size = (F32)ctrl->getValue().asReal(); - gSavedSettings.setF32("LandBrushSize", size); -} - -void commit_slider_dozer_force(LLUICtrl *ctrl, void*) +void commit_slider_dozer_force(LLUICtrl *ctrl) { // the slider is logarithmic, so we exponentiate to get the actual force multiplier F32 dozer_force = pow(10.f, (F32)ctrl->getValue().asReal()); gSavedSettings.setF32("LandBrushForce", dozer_force); } -void click_apply_to_selection(void* user) +void click_apply_to_selection(void*) { LLToolBrushLand::getInstance()->modifyLandInSelectionGlobal(); } -void commit_radio_group_edit(LLUICtrl *ctrl, void *data) +void commit_radio_group_edit(LLUICtrl *ctrl) { S32 show_owners = gSavedSettings.getBOOL("ShowParcelOwners"); @@ -881,7 +871,7 @@ void commit_radio_group_edit(LLUICtrl *ctrl, void *data) gSavedSettings.setBOOL("ShowParcelOwners", show_owners); } -void commit_radio_group_land(LLUICtrl* ctrl, void* data) +void commit_radio_group_land(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -909,7 +899,7 @@ void commit_radio_group_land(LLUICtrl* ctrl, void* data) } } -void commit_select_component(LLUICtrl *ctrl, void *data) +void commit_select_component(void *data) { LLFloaterTools* floaterp = (LLFloaterTools*)data; @@ -933,7 +923,7 @@ void commit_select_component(LLUICtrl *ctrl, void *data) } } -void commit_grid_mode(LLUICtrl *ctrl, void *data) +void commit_grid_mode(LLUICtrl *ctrl) { LLComboBox* combo = (LLComboBox*)ctrl; @@ -948,10 +938,9 @@ void LLFloaterTools::setObjectType( LLPCode pcode ) gFocusMgr.setMouseCapture(NULL); } -// static -void LLFloaterTools::onClickGridOptions(void* data) + +void LLFloaterTools::onClickGridOptions() { - //LLFloaterTools* floaterp = (LLFloaterTools*)data; LLFloaterReg::showInstance("build_options"); // RN: this makes grid options dependent on build tools window //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); @@ -964,8 +953,558 @@ void LLFloaterTools::setEditTool(void* tool_pointer) LLToolMgr::getInstance()->getCurrentToolset()->selectTool( tool ); } +void LLFloaterTools::setTool(const LLSD& user_data) +{ + std::string control_name = user_data.asString(); + if(control_name == "Focus") + LLToolMgr::getInstance()->getCurrentToolset()->selectTool((LLTool *) LLToolCamera::getInstance() ); + else if (control_name == "Move" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *)LLToolGrab::getInstance() ); + else if (control_name == "Edit" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompTranslate::getInstance()); + else if (control_name == "Create" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompCreate::getInstance()); + else if (control_name == "Land" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolSelectLand::getInstance()); + else + llwarns<<" no parameter name "<setCurrentToolset(gBasicToolset); LLFloater::onFocusReceived(); } + +// Media stuff +void LLFloaterTools::refreshMedia() +{ + getMediaState(); + LLFloaterMediaSettings::getInstance(); + LLFloaterMediaSettings::initValues(mMediaSettings ); +} + + + +void LLFloaterTools::getMediaState() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + if( !objectp ) + { + childSetEnabled("media_tex", FALSE); + childSetEnabled("add_media", FALSE); + childSetEnabled("delete_media", FALSE); + childSetEnabled("edit_media", FALSE); + updateMediaSettings(); + return; + } + + bool editable = gAgent.isGodlike() || (objectp->permModify() && objectp->getPCode() == LL_PCODE_VOLUME); + + // Media settings + U8 has_media = (U8)0; + struct media_functor : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 face) + { + return (object->getTE(face)->getMediaTexGen()); + } + } func; + bool identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, has_media ); + + // update UI depending on whether "object" (prim or face) has media + // and whether or not you are allowed to edit it. + bool bool_has_media = (has_media & LLTextureEntry::MF_HAS_MEDIA); + childSetEnabled("media_tex", bool_has_media & editable); + childSetEnabled( "edit_media", bool_has_media & editable ); + childSetEnabled( "delete_media", bool_has_media & editable ); + childSetEnabled( "add_media", ( ! bool_has_media ) & editable ); + + // load values for media settings + updateMediaSettings(); + + // if identical is set, all faces are same + if ( identical ) + { + // TODO: display a list of all media on the face - use 'identical' flag + }; +} + + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to add media to a prim or prim face +void LLFloaterTools::onClickBtnAddMedia() +{ + // check for the edit tool and now many faces are selected + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + if((tool != LLToolFace::getInstance()) || LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected()) + { + LLNotifications::instance().add("MultipleFacesSelected",LLSD(), LLSD(), multipleFacesSelectedConfirm); + + } + else + { + onClickBtnEditMedia(); + } + +} + +// static +bool LLFloaterTools::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + gFloaterTools->onClickBtnEditMedia(); + break; + case 1: // "No" + default: + break; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to edit existing media settings on a prim or prim face +// TODO: test if there is media on the item and only allow editing if present +void LLFloaterTools::onClickBtnEditMedia() +{ + refreshMedia(); + LLFloaterReg::showInstance("media_settings"); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to delete media from a prim or prim face +void LLFloaterTools::onClickBtnDeleteMedia() +{ + LLNotifications::instance().add("DeleteMedia", LLSD(), LLSD(), deleteMediaConfirm); +} + + +// static +bool LLFloaterTools::deleteMediaConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + LLSelectMgr::getInstance()->selectionSetMedia( 0 ); + if(LLFloaterReg::instanceVisible("media_settings")) + { + LLFloaterReg::hideInstance("media_settings"); + } + break; + + case 1: // "No" + default: + break; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterTools::updateMediaSettings() +{ + bool identical( false ); + std::string base_key( "" ); + std::string value_str( "" ); + int value_int = 0; + bool value_bool = false; + LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); + // TODO: (CP) refactor this using something clever or boost or both !! + + LLMediaEntry default_media_data; + + // controls + U8 value_u8 = default_media_data.getControls(); + struct functor_getter_controls : public LLSelectedTEGetFunctor< U8 > + { + U8 get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getControls(); + LLMediaEntry default_media_data; + return default_media_data.getControls(); + }; + + } func_controls; + identical = selected_objects->getSelectedTEValue( &func_controls, value_u8 ); + base_key = std::string( LLMediaEntry::CONTROLS_KEY ); + mMediaSettings[ base_key ] = value_u8; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // First click (formerly left click) + value_bool = default_media_data.getFirstClickInteract(); + struct functor_getter_first_click : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getFirstClickInteract(); + LLMediaEntry default_media_data; + return default_media_data.getFirstClickInteract(); + }; + + } func_first_click; + identical = selected_objects->getSelectedTEValue( &func_first_click, value_bool ); + base_key = std::string( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Home URL + value_str = default_media_data.getHomeURL(); + struct functor_getter_home_url : public LLSelectedTEGetFunctor< std::string > + { + std::string get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getHomeURL(); + LLMediaEntry default_media_data; + return default_media_data.getHomeURL(); + }; + + } func_home_url; + identical = selected_objects->getSelectedTEValue( &func_home_url, value_str ); + base_key = std::string( LLMediaEntry::HOME_URL_KEY ); + mMediaSettings[ base_key ] = value_str; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + llwarns<<"Angela debug : home url string == "< + { + std::string get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getCurrentURL(); + LLMediaEntry default_media_data; + return default_media_data.getCurrentURL(); + }; + + } func_current_url; + identical = selected_objects->getSelectedTEValue( &func_current_url, value_str ); + base_key = std::string( LLMediaEntry::CURRENT_URL_KEY ); + mMediaSettings[ base_key ] = value_str; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto zoom + value_bool = default_media_data.getAutoZoom(); + struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoZoom(); + LLMediaEntry default_media_data; + return default_media_data.getAutoZoom(); + }; + + } func_auto_zoom; + identical = selected_objects->getSelectedTEValue( &func_auto_zoom, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_ZOOM_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto play + value_bool = default_media_data.getAutoPlay(); + struct functor_getter_auto_play : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoPlay(); + LLMediaEntry default_media_data; + return default_media_data.getAutoPlay(); + }; + + } func_auto_play; + identical = selected_objects->getSelectedTEValue( &func_auto_play, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_PLAY_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto scale + value_bool = default_media_data.getAutoScale(); + struct functor_getter_auto_scale : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoScale(); + LLMediaEntry default_media_data; + return default_media_data.getAutoScale();; + }; + + } func_auto_scale; + identical = selected_objects->getSelectedTEValue( &func_auto_scale, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_SCALE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto loop + value_bool = default_media_data.getAutoLoop(); + struct functor_getter_auto_loop : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoLoop(); + LLMediaEntry default_media_data; + return default_media_data.getAutoLoop(); + }; + + } func_auto_loop; + identical = selected_objects->getSelectedTEValue( &func_auto_loop, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_LOOP_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // width pixels (if not auto scaled) + value_int = default_media_data.getWidthPixels(); + struct functor_getter_width_pixels : public LLSelectedTEGetFunctor< int > + { + int get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWidthPixels(); + LLMediaEntry default_media_data; + return default_media_data.getWidthPixels(); + }; + + } func_width_pixels; + identical = selected_objects->getSelectedTEValue( &func_width_pixels, value_int ); + base_key = std::string( LLMediaEntry::WIDTH_PIXELS_KEY ); + mMediaSettings[ base_key ] = value_int; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // height pixels (if not auto scaled) + value_int = default_media_data.getHeightPixels(); + struct functor_getter_height_pixels : public LLSelectedTEGetFunctor< int > + { + int get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getHeightPixels(); + LLMediaEntry default_media_data; + return default_media_data.getHeightPixels(); + }; + + } func_height_pixels; + identical = selected_objects->getSelectedTEValue( &func_height_pixels, value_int ); + base_key = std::string( LLMediaEntry::HEIGHT_PIXELS_KEY ); + mMediaSettings[ base_key ] = value_int; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Enable Alt image + value_bool = default_media_data.getAltImageEnable(); + struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAltImageEnable(); + LLMediaEntry default_media_data; + return default_media_data.getAltImageEnable(); + }; + + } func_enable_alt_image; + identical = selected_objects->getSelectedTEValue( &func_enable_alt_image, value_bool ); + base_key = std::string( LLMediaEntry::ALT_IMAGE_ENABLE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - owner interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); + struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); + }; + + } func_perms_owner_interact; + identical = selected_objects->getSelectedTEValue( &func_perms_owner_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_OWNER_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - owner control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); + struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); + }; + + } func_perms_owner_control; + identical = selected_objects ->getSelectedTEValue( &func_perms_owner_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_OWNER_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - group interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); + struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); + }; + + } func_perms_group_interact; + identical = selected_objects->getSelectedTEValue( &func_perms_group_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_GROUP_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - group control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); + struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); + }; + + } func_perms_group_control; + identical = selected_objects->getSelectedTEValue( &func_perms_group_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_GROUP_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - anyone interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); + struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); + }; + + } func_perms_anyone_interact; + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_perms_anyone_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_ANYONE_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - anyone control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); + struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); + }; + + } func_perms_anyone_control; + identical = selected_objects->getSelectedTEValue( &func_perms_anyone_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_ANYONE_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // security - whitelist enable + value_bool = default_media_data.getWhiteListEnable(); + struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWhiteListEnable(); + LLMediaEntry default_media_data; + return default_media_data.getWhiteListEnable(); + }; + + } func_whitelist_enable; + identical = selected_objects->getSelectedTEValue( &func_whitelist_enable, value_bool ); + base_key = std::string( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // security - whitelist URLs + std::vector value_vector_str = default_media_data.getWhiteList(); + struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector > + { + std::vector get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWhiteList(); + LLMediaEntry default_media_data; + return default_media_data.getWhiteList(); + }; + + } func_whitelist_urls; + identical = selected_objects->getSelectedTEValue( &func_whitelist_urls, value_vector_str ); + base_key = std::string( LLMediaEntry::WHITELIST_KEY ); + mMediaSettings[ base_key ].clear(); + std::vector< std::string >::iterator iter = value_vector_str.begin(); + while( iter != value_vector_str.end() ) + { + std::string white_list_url = *iter; + mMediaSettings[ base_key ].append( white_list_url ); + ++iter; + }; + + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; +} + diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 1b9f1d31ec..008c9677ed 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -100,13 +100,24 @@ public: void setStatusText(const std::string& text); static void setEditTool(void* data); + void setTool(const LLSD& user_data); void saveLastTool(); + void onClickBtnDeleteMedia(); + void onClickBtnAddMedia(); + void onClickBtnEditMedia(); + + private: void onClose(); void refresh(); - + void refreshMedia(); + void getMediaState(); + void updateMediaSettings(); + void getMeidaState(); + static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); + static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); static void setObjectType( LLPCode pcode ); - static void onClickGridOptions(void* data); + void onClickGridOptions(); public: LLButton *mBtnFocus; @@ -175,6 +186,10 @@ private: BOOL mDirty; std::map mStatusText; + +protected: + LLSD mMediaSettings; + }; extern LLFloaterTools *gFloaterTools; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 1e975cd447..2b01a56373 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -35,6 +35,7 @@ #include "llfloaterurlentry.h" #include "llpanellandmedia.h" +#include "llpanelface.h" // project includes #include "llcombobox.h" @@ -145,13 +146,23 @@ void LLFloaterURLEntry::buildURLHistory() void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) { - LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get(); + LLPanelLandMedia* panel_media = dynamic_cast(mPanelLandMediaHandle.get()); if (panel_media) { // status is ignored for now -- error = "none/none" panel_media->setMediaType(mime_type); panel_media->setMediaURL(mMediaURLEdit->getValue().asString()); } + else + { + LLPanelFace* panel_face = dynamic_cast(mPanelLandMediaHandle.get()); + if(panel_face) + { + panel_face->setMediaType(mime_type); + panel_face->setMediaURL(mMediaURLEdit->getValue().asString()); + } + + } // Decrement the cursor getWindow()->decBusyCount(); childSetVisible("loading_label", false); @@ -159,29 +170,18 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_ } // static -LLHandle LLFloaterURLEntry::show(LLHandle parent) +LLHandle LLFloaterURLEntry::show(LLHandle parent, const std::string media_url) { - if (sInstance) - { - sInstance->openFloater(); - } - else + if (!sInstance) { sInstance = new LLFloaterURLEntry(parent); } - sInstance->updateFromLandMediaPanel(); + sInstance->openFloater(); + sInstance->addURLToCombobox(media_url); return sInstance->getHandle(); } -void LLFloaterURLEntry::updateFromLandMediaPanel() -{ - LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get(); - if (panel_media) - { - std::string media_url = panel_media->getMediaURL(); - addURLToCombobox(media_url); - } -} + bool LLFloaterURLEntry::addURLToCombobox(const std::string& media_url) { diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 0aeca823b8..6dd9c8453c 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -44,10 +44,8 @@ class LLFloaterURLEntry : public LLFloater public: // Can only be shown by LLPanelLandMedia, and pushes data back into // that panel via the handle. - static LLHandle show(LLHandle panel_land_media_handle); + static LLHandle show(LLHandle panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); - void updateFromLandMediaPanel(); - void headerFetchComplete(U32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwhitelistentry.cpp b/indra/newview/llfloaterwhitelistentry.cpp new file mode 100644 index 0000000000..551a5191fc --- /dev/null +++ b/indra/newview/llfloaterwhitelistentry.cpp @@ -0,0 +1,97 @@ +/** + * @file llfloaterwhitelistentry.cpp + * @brief LLFloaterWhistListEntry class implementation + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" +#include "llfloatermediasettings.h" +#include "llfloaterwhitelistentry.h" +#include "llpanelmediasettingssecurity.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "lllineeditor.h" + + +/////////////////////////////////////////////////////////////////////////////// +// +LLFloaterWhiteListEntry::LLFloaterWhiteListEntry( const LLSD& key ) : + LLFloater(key) +{ +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_whitelist_entry.xml"); +} + +/////////////////////////////////////////////////////////////////////////////// +// +LLFloaterWhiteListEntry::~LLFloaterWhiteListEntry() +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +BOOL LLFloaterWhiteListEntry::postBuild() +{ + mWhiteListEdit = getChild("whitelist_entry"); + + childSetAction("cancel_btn", onBtnCancel, this); + childSetAction("ok_btn", onBtnOK, this); + + setDefaultBtn("ok_btn"); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterWhiteListEntry::onBtnOK( void* userdata ) +{ + LLFloaterWhiteListEntry *self =(LLFloaterWhiteListEntry *)userdata; + + LLPanelMediaSettingsSecurity* panel = LLFloaterReg::getTypedInstance("media_settings")->getPanelSecurity(); + if ( panel ) + { + std::string white_list_item = self->mWhiteListEdit->getText(); + + panel->addWhiteListItem( white_list_item ); + }; + + self->closeFloater(); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterWhiteListEntry::onBtnCancel( void* userdata ) +{ + LLFloaterWhiteListEntry *self =(LLFloaterWhiteListEntry *)userdata; + + self->closeFloater(); +} diff --git a/indra/newview/llfloaterwhitelistentry.h b/indra/newview/llfloaterwhitelistentry.h new file mode 100644 index 0000000000..8ab5fb78b9 --- /dev/null +++ b/indra/newview/llfloaterwhitelistentry.h @@ -0,0 +1,56 @@ +/** + * @file llfloaterwhitelistentry.h + * @brief LLFloaterWhiteListEntry class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERWHITELISTENTRY_H +#define LL_LLFLOATERWHITELISTENTRY_H + +#include "llfloater.h" + +class LLLineEditor; + +class LLFloaterWhiteListEntry : + public LLFloater +{ + public: + LLFloaterWhiteListEntry(const LLSD& key); + ~LLFloaterWhiteListEntry(); + + BOOL postBuild(); + + private: + LLLineEditor* mWhiteListEdit; + + static void onBtnOK(void*); + static void onBtnCancel(void*); +}; + +#endif // LL_LLFLOATERWHITELISTENTRY_H diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 6ec098b92b..b996c15a7d 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -43,6 +43,7 @@ #include "llviewborder.h" #include "llviewercontrol.h" #include "llviewermedia.h" +#include "llviewertexture.h" #include "llviewerwindow.h" #include "llnotifications.h" #include "llweb.h" @@ -63,6 +64,9 @@ LLMediaCtrl::Params::Params() border_visible("border_visible", true), ignore_ui_scale("ignore_ui_scale", true), hide_loading("hide_loading", false), + decouple_texture_size("decouple_texture_size", false), + texture_width("texture_width", 1024), + texture_height("texture_height", 1024), caret_color("caret_color") {} @@ -82,10 +86,12 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mMediaSource( 0 ), mTakeFocusOnClick( true ), mCurrentNavUrl( "" ), - mLastSetCursor( UI_CURSOR_ARROW ), mStretchToFill( true ), mMaintainAspectRatio ( true ), - mHideLoading (false) + mHideLoading (false), + mDecoupleTextureSize ( false ), + mTextureWidth ( 1024 ), + mTextureHeight ( 1024 ) { { LLColor4 color = p.caret_color().get(); @@ -99,24 +105,29 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : setBorderVisible(p.border_visible()); mHideLoading = p.hide_loading(); + + setDecoupleTextureSize(p.decouple_texture_size()); + + setTextureSize(p.texture_width(), p.texture_height()); - S32 screen_width = mIgnoreUIScale ? - llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); - S32 screen_height = mIgnoreUIScale ? - llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + if(!getDecoupleTextureSize()) + { + S32 screen_width = mIgnoreUIScale ? + llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); + S32 screen_height = mIgnoreUIScale ? + llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + + setTextureSize(screen_width, screen_height); + } mMediaTextureID.generate(); - mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, mMediaTextureID, screen_width, screen_height, false, false, "text/html"); - if ( !mMediaSource ) + + // We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to. + if(!mHomePageUrl.empty()) { - llwarns << "media source create failed " << llendl; - // return; + navigateHome(); } - - mMediaSource->setVisible( getVisible() ); - - mMediaSource->addObserver( this ); - + // FIXME: How do we create a bevel now? // LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); // mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); @@ -179,9 +190,10 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) convertInputCoords(x, y); if (mMediaSource) + { mMediaSource->mouseMove(x, y); - - gViewerWindow->setCursor(mLastSetCursor); + gViewerWindow->setCursor(mMediaSource->getLastSetCursor()); + } return TRUE; } @@ -389,19 +401,19 @@ void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility ) // void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) { - S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; - S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; - -// llinfos << "reshape called with width = " << width << ", height = " << height << llendl; - - // when floater is minimized, these sizes are negative - if ( screen_height > 0 && screen_width > 0 ) + if(!getDecoupleTextureSize()) { - mMediaSource->setSize(screen_width, screen_height); - mForceUpdate = true; - } + S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; + S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; - LLPanel::reshape( width, height, called_from_parent ); + // when floater is minimized, these sizes are negative + if ( screen_height > 0 && screen_width > 0 ) + { + setTextureSize(screen_width, screen_height); + } + } + + LLUICtrl::reshape( width, height, called_from_parent ); } //////////////////////////////////////////////////////////////////////////////// @@ -475,9 +487,10 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) return; } - if (mMediaSource) + if (ensureMediaSourceExists()) { mCurrentNavUrl = url_in; + mMediaSource->setSize(mTextureWidth, mTextureHeight); mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); } } @@ -513,9 +526,10 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str return; } } - if (mMediaSource) + if (ensureMediaSourceExists()) { mCurrentNavUrl = expanded_filename; + mMediaSource->setSize(mTextureWidth, mTextureHeight); mMediaSource->navigateTo(expanded_filename, "text/html", false); } @@ -525,11 +539,11 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str // void LLMediaCtrl::navigateHome() { - if( mHomePageUrl.length() ) + if (ensureMediaSourceExists()) { - if (mMediaSource) - mMediaSource->navigateTo(mHomePageUrl); - }; + mMediaSource->setSize(mTextureWidth, mTextureHeight); + mMediaSource->navigateHome(); + } } //////////////////////////////////////////////////////////////////////////////// @@ -537,6 +551,10 @@ void LLMediaCtrl::navigateHome() void LLMediaCtrl::setHomePageUrl( const std::string urlIn ) { mHomePageUrl = urlIn; + if (mMediaSource) + { + mMediaSource->setHomeURL(mHomePageUrl); + } } //////////////////////////////////////////////////////////////////////////////// @@ -546,6 +564,21 @@ bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned i //NOOP return false; } + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setTextureSize(S32 width, S32 height) +{ + mTextureWidth = width; + mTextureHeight = height; + + if(mMediaSource) + { + mMediaSource->setSize(mTextureWidth, mTextureHeight); + mForceUpdate = true; + } +} + //////////////////////////////////////////////////////////////////////////////// // std::string LLMediaCtrl::getHomePageUrl() @@ -553,6 +586,38 @@ std::string LLMediaCtrl::getHomePageUrl() return mHomePageUrl; } +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::ensureMediaSourceExists() +{ + if(mMediaSource.isNull()) + { + // If we don't already have a media source, try to create one. + mMediaSource = LLViewerMedia::newMediaImpl(mMediaTextureID, mTextureWidth, mTextureHeight); + if ( mMediaSource ) + { + mMediaSource->setUsedInUI(true); + mMediaSource->setHomeURL(mHomePageUrl); + mMediaSource->setVisible( getVisible() ); + mMediaSource->addObserver( this ); + } + else + { + llwarns << "media source create failed " << llendl; + // return; + } + } + + return !mMediaSource.isNull(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::unloadMediaSource() +{ + mMediaSource = NULL; +} + //////////////////////////////////////////////////////////////////////////////// // LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() @@ -574,13 +639,17 @@ void LLMediaCtrl::draw() { return; } + + if(!media_plugin || (!media_plugin->textureValid())) + { + // Don't try to draw without a valid texture + return; + } LLViewerMediaTexture* media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID); if (!media_texture ) - { return; - } if ( gRestoreGL == 1 ) { @@ -658,7 +727,7 @@ void LLMediaCtrl::draw() width = llmin(media_plugin->getWidth(), r.getWidth()); height = llmin(media_plugin->getHeight(), r.getHeight()); } - + x_offset = (r.getWidth() - width) / 2; y_offset = (r.getHeight() - height) / 2; @@ -774,24 +843,9 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_CURSOR_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; - - std::string cursor = self->getCursorName(); - - if(cursor == "arrow") - mLastSetCursor = UI_CURSOR_ARROW; - else if(cursor == "ibeam") - mLastSetCursor = UI_CURSOR_IBEAM; - else if(cursor == "splith") - mLastSetCursor = UI_CURSOR_SIZEWE; - else if(cursor == "splitv") - mLastSetCursor = UI_CURSOR_SIZENS; - else if(cursor == "hand") - mLastSetCursor = UI_CURSOR_HAND; - else // for anything else, default to the arrow - mLastSetCursor = UI_CURSOR_ARROW; - }; + } break; - + case MEDIA_EVENT_NAVIGATE_BEGIN: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index a19b3ad67b..5ea03f1e6c 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -37,7 +37,6 @@ #include "lluictrl.h" #include "llframetimer.h" -#include "lldynamictexture.h" class LLViewBorder; class LLUICtrlFactory; @@ -50,7 +49,6 @@ class LLMediaCtrl : public LLViewerMediaEventEmitter { LOG_CLASS(LLMediaCtrl); - public: struct Params : public LLInitParam::Block { @@ -58,7 +56,11 @@ public: Optional border_visible, ignore_ui_scale, - hide_loading; + hide_loading, + decouple_texture_size; + + Optional texture_width, + texture_height; Optional caret_color; @@ -127,9 +129,17 @@ public: void setForceUpdate(bool force_update) { mForceUpdate = force_update; } bool getForceUpdate() { return mForceUpdate; } + bool ensureMediaSourceExists(); + void unloadMediaSource(); + LLPluginClassMedia* getMediaPlugin(); bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ); + + void setDecoupleTextureSize(bool decouple) { mDecoupleTextureSize = decouple; } + bool getDecoupleTextureSize() { return mDecoupleTextureSize; } + + void setTextureSize(S32 width, S32 height); // over-rides @@ -173,10 +183,12 @@ public: bool mAlwaysRefresh; viewer_media_t mMediaSource; bool mTakeFocusOnClick; - ECursorType mLastSetCursor; bool mStretchToFill; bool mMaintainAspectRatio; bool mHideLoading; + bool mDecoupleTextureSize; + S32 mTextureWidth; + S32 mTextureHeight; }; #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 5da646497b..ea528a1df8 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -72,6 +72,13 @@ // // Globals // +const char* LLPanelContents::TENTATIVE_SUFFIX = "_tentative"; +const char* LLPanelContents::PERMS_OWNER_INTERACT_KEY = "perms_owner_interact"; +const char* LLPanelContents::PERMS_OWNER_CONTROL_KEY = "perms_owner_control"; +const char* LLPanelContents::PERMS_GROUP_INTERACT_KEY = "perms_group_interact"; +const char* LLPanelContents::PERMS_GROUP_CONTROL_KEY = "perms_group_control"; +const char* LLPanelContents::PERMS_ANYONE_INTERACT_KEY = "perms_anyone_interact"; +const char* LLPanelContents::PERMS_ANYONE_CONTROL_KEY = "perms_anyone_control"; BOOL LLPanelContents::postBuild() { @@ -83,7 +90,7 @@ BOOL LLPanelContents::postBuild() childSetAction("button permissions",&LLPanelContents::onClickPermissions, this); mPanelInventory = getChild("contents_inventory"); - + return TRUE; } @@ -112,7 +119,7 @@ void LLPanelContents::getState(LLViewerObject *objectp ) LLSelectMgr::getInstance()->selectGetGroup(group_id); // sets group_id as a side effect SL-23488 // BUG? Check for all objects being editable? - BOOL editable = gAgent.isGodlike() + bool editable = gAgent.isGodlike() || (objectp->permModify() && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) ))); // solves SL-23488 BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ); @@ -123,8 +130,8 @@ void LLPanelContents::getState(LLViewerObject *objectp ) all_volume && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))); -} +} void LLPanelContents::refresh() { @@ -135,7 +142,7 @@ void LLPanelContents::refresh() if (mPanelInventory) { mPanelInventory->refresh(); - } + } } diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index de1914bff9..bab980b524 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -51,11 +51,23 @@ public: void refresh(); - static void onClickNewScript( void* userdata); - static void onClickPermissions( void* userdata); + + static void onClickNewScript(void*); + static void onClickPermissions(void*); + + // Key suffix for "tentative" fields + static const char* TENTATIVE_SUFFIX; + + // These aren't fields in LLMediaEntry, so we have to define them ourselves for checkbox control + static const char* PERMS_OWNER_INTERACT_KEY; + static const char* PERMS_OWNER_CONTROL_KEY; + static const char* PERMS_GROUP_INTERACT_KEY; + static const char* PERMS_GROUP_CONTROL_KEY; + static const char* PERMS_ANYONE_INTERACT_KEY; + static const char* PERMS_ANYONE_CONTROL_KEY; protected: - void getState(LLViewerObject *object); + void getState(LLViewerObject *object); public: LLPanelInventory* mPanelInventory; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 08a50d4b6e..c61b987b1c 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -49,6 +49,7 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "lllineeditor.h" +#include "llmediaentry.h" #include "llresmgr.h" #include "llselectmgr.h" #include "llspinctrl.h" @@ -61,6 +62,7 @@ #include "llviewermedia.h" #include "llviewerobject.h" #include "llviewerstats.h" +#include "llvovolume.h" #include "lluictrlfactory.h" #include "llpluginclassmedia.h" @@ -70,6 +72,18 @@ BOOL LLPanelFace::postBuild() { + childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); + childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this); + childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this); + childSetAction("button apply",&LLPanelFace::onClickApply,this); + childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this); + childSetAction("button align",&LLPanelFace::onClickAutoFix,this); + LLRect rect = this->getRect(); LLTextureCtrl* mTextureCtrl; LLColorSwatchCtrl* mColorSwatch; @@ -91,7 +105,7 @@ BOOL LLPanelFace::postBuild() mTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitTexture, this, _2) ); mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); - mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, _2)); + mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); mTextureCtrl->setFollowsTop(); mTextureCtrl->setFollowsLeft(); // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode @@ -161,17 +175,6 @@ BOOL LLPanelFace::postBuild() mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } - childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); - childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this); - childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this); - childSetAction("button apply",&onClickApply,this); - childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this); - childSetAction("button align",onClickAutoFix,this); clearCtrls(); @@ -382,10 +385,8 @@ void LLPanelFace::getState() BOOL editable = objectp->permModify(); // only turn on auto-adjust button if there is a media renderer and the media is loaded - childSetEnabled("textbox autofix",FALSE); - //mLabelTexAutoFix->setEnabled ( FALSE ); - childSetEnabled("button align",FALSE); - //mBtnAutoFix->setEnabled ( FALSE ); + childSetEnabled("textbox autofix", editable); + childSetEnabled("button align", editable); //if ( LLMediaEngine::getInstance()->getMediaRenderer () ) // if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () ) @@ -785,6 +786,9 @@ void LLPanelFace::getState() childSetEnabled("button align",FALSE); childSetEnabled("button apply",FALSE); + childSetEnabled("has media", FALSE); + childSetEnabled("media info set", FALSE); + } } @@ -862,7 +866,7 @@ void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata) } // static -BOOL LLPanelFace::onDragTexture(LLInventoryItem* item) +BOOL LLPanelFace::onDragTexture(LLUICtrl*, LLInventoryItem* item) { BOOL accept = TRUE; for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); @@ -917,15 +921,25 @@ void LLPanelFace::onClickApply(void* userdata) LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter ); } -// commit the fit media texture to prim button - struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor { virtual bool apply(LLViewerObject* object, S32 te) { - // TODO: the media impl pointer should actually be stored by the texture - viewer_media_t pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(object->getTE ( te )->getID()); - // only do this if it's a media texture + viewer_media_t pMediaImpl; + + const LLTextureEntry* tep = object->getTE(te); + const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; + if ( mep ) + { + pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + } + + if ( pMediaImpl.isNull()) + { + // If we didn't find face media for this face, check whether this face is showing parcel media. + pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + } + if ( pMediaImpl.notNull()) { LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); @@ -957,3 +971,14 @@ void LLPanelFace::onClickAutoFix(void* userdata) LLPanelFaceSendFunctor sendfunc; LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); } + + + +// TODO: I don't know who put these in or what these are for??? +void LLPanelFace::setMediaURL(const std::string& url) +{ +} +void LLPanelFace::setMediaType(const std::string& mime_type) +{ +} + diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 9600129696..6a8704ce14 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,6 +47,7 @@ class LLTextBox; class LLTextureCtrl; class LLUICtrl; class LLViewerObject; +class LLFloater; class LLPanelFace : public LLPanel { @@ -56,6 +57,8 @@ public: virtual ~LLPanelFace(); void refresh(); + void setMediaURL(const std::string& url); + void setMediaType(const std::string& mime_type); protected: void getState(); @@ -69,9 +72,10 @@ protected: void sendShiny(); // applies and sends shininess void sendFullbright(); // applies and sends full bright void sendGlow(); + void sendMedia(); // this function is to return TRUE if the drag should succeed. - static BOOL onDragTexture(LLInventoryItem* item); + static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item); void onCommitTexture(const LLSD& data); void onCancelTexture(const LLSD& data); @@ -87,10 +91,11 @@ protected: static void onCommitShiny( LLUICtrl* ctrl, void* userdata); static void onCommitFullbright( LLUICtrl* ctrl, void* userdata); static void onCommitGlow( LLUICtrl* ctrl, void *userdata); - + static void onClickApply(void*); static void onClickAutoFix(void*); static F32 valueGlow(LLViewerObject* object, S32 face); + }; #endif diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index 994bf7e3f9..42ad9820a8 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -122,9 +122,6 @@ BOOL LLPanelLandMedia::postBuild() mSetURLButton = getChild("set_media_url"); childSetAction("set_media_url", onSetBtn, this); - mResetURLButton = getChild("reset_media_url"); - childSetAction("reset_media_url", onResetBtn, this); - return TRUE; } @@ -215,13 +212,7 @@ void LLPanelLandMedia::refresh() mMediaTextureCtrl->setEnabled( can_change_media ); mSetURLButton->setEnabled( can_change_media ); - mResetURLButton->setEnabled( can_change_media ); - LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mURLEntryFloater.get(); - if (floater_url_entry) - { - floater_url_entry->updateFromLandMediaPanel(); - } } } @@ -341,7 +332,7 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) void LLPanelLandMedia::onSetBtn(void *userdata) { LLPanelLandMedia *self = (LLPanelLandMedia *)userdata; - self->mURLEntryFloater = LLFloaterURLEntry::show( self->getHandle() ); + self->mURLEntryFloater = LLFloaterURLEntry::show( self->getHandle(), self->getMediaURL() ); LLFloater* parent_floater = gFloaterView->getParentFloater(self); if (parent_floater) { diff --git a/indra/newview/llpanellandmedia.h b/indra/newview/llpanellandmedia.h index 5ad1f9758d..3deea29d17 100644 --- a/indra/newview/llpanellandmedia.h +++ b/indra/newview/llpanellandmedia.h @@ -63,8 +63,6 @@ private: LLLineEditor* mMediaDescEdit; LLComboBox* mMediaTypeCombo; LLButton* mSetURLButton; - LLButton* mResetURLButton; - LLSpinCtrl* mMediaResetCtrl; LLSpinCtrl* mMediaHeightCtrl; LLSpinCtrl* mMediaWidthCtrl; LLTextBox* mMediaResetCtrlLabel; @@ -74,13 +72,6 @@ private: LLCheckBoxCtrl* mMediaLoopCheck; LLCheckBoxCtrl* mMediaUrlCheck; LLHandle mURLEntryFloater; - LLCheckBoxCtrl* mMediaNavigateAllowCheck; - LLCheckBoxCtrl* mMediaURLFilterCheck; - LLLineEditor* mMediaURLFilterDomainEdit; - LLButton* mMediaURLFilterAddButton; - LLButton* mMediaURLFilterRemoveButton; - LLScrollListCtrl* mURLFilterList; - LLRadioGroup* mRadioNavigateControl; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index daf0fbd5e0..a7f66f3293 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -70,6 +70,7 @@ #include "llmediactrl.h" #include "llrootview.h" + #include "llfloatertos.h" #include "lltrans.h" #include "llglheaders.h" diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp new file mode 100644 index 0000000000..be40d6fb5f --- /dev/null +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -0,0 +1,409 @@ +/** + * @file llpanelmediasettingsgeneral.cpp + * @brief LLPanelMediaSettingsGeneral class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmediasettingsgeneral.h" +#include "llcombobox.h" +#include "llcheckboxctrl.h" +#include "llspinctrl.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llbutton.h" +#include "lltexturectrl.h" +#include "llurl.h" +#include "llwindow.h" +#include "llmediaentry.h" +#include "llmediactrl.h" +#include "llpanelcontents.h" +#include "llpluginclassmedia.h" +#include "llfloatermediasettings.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() : + mControls( NULL ), + mAutoLoop( NULL ), + mFirstClick( NULL ), + mAutoZoom( NULL ), + mAutoPlay( NULL ), + mAutoScale( NULL ), + mWidthPixels( NULL ), + mHeightPixels( NULL ), + mHomeURL( NULL ), + mCurrentURL( NULL ), + mAltImageEnable( NULL ), + mParent( NULL ) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml"); + mCommitCallbackRegistrar.add("Media.ResetCurrentUrl", boost::bind(&LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl, this)); +// mCommitCallbackRegistrar.add("Media.CommitHomeURL", boost::bind(&LLPanelMediaSettingsGeneral::onCommitHomeURL, this)); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsGeneral::postBuild() +{ + // connect member vars with UI widgets + mAltImageEnable = getChild< LLCheckBoxCtrl >( LLMediaEntry::ALT_IMAGE_ENABLE_KEY ); + mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY ); + mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY ); + mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY ); + mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY ); + mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY ); + mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY ); + mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); + mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY ); + mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY ); + mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY ); + mPreviewMedia = getChild("preview_media"); + + // watch commit action for HOME URL + childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this); + + // interrogates controls and updates widgets as required + updateMediaPreview(); + updateCurrentURL(); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::draw() +{ + // housekeeping + LLPanel::draw(); + + // enable/disable pixel values image entry based on auto scale checkbox + if ( mAutoScale->getValue().asBoolean() == false ) + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false ); + }; + + // enable/disable UI based on type of media + bool reset_button_is_active = true; + if( mPreviewMedia ) + { + LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); + if( media_plugin ) + { + // some controls are only appropriate for time or browser type plugins + // so we selectively enable/disable them - need to do it in draw + // because the information from plugins arrives assynchronously + bool show_time_controls = media_plugin->pluginSupportsMediaTime(); + if ( show_time_controls ) + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false ); + reset_button_is_active = false; + childSetEnabled( "current_url_label", false ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true ); + reset_button_is_active = true; + childSetEnabled( "current_url_label", true ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false ); + }; + }; + }; + + // current URL can change over time. + updateCurrentURL(); + + // enable/disable RESRET button depending on permissions + // since this is the same as a navigate action + U32 owner_mask_on; + U32 owner_mask_off; + U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_OWNER, + &owner_mask_on, &owner_mask_off ); + U32 group_mask_on; + U32 group_mask_off; + U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_GROUP, + &group_mask_on, &group_mask_off ); + U32 everyone_mask_on; + U32 everyone_mask_off; + S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_EVERYONE, + &everyone_mask_on, &everyone_mask_off ); + + bool user_can_press_reset = false; + + // if perms we got back are valid + if ( valid_owner_perms && + valid_group_perms && + valid_everyone_perms ) + { + // if user is allowed to press the RESET button + if ( ( owner_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) ) + { + user_can_press_reset = true; + } + else + // user is NOT allowed to press the RESET button + { + user_can_press_reset = false; + }; + }; + + // several places modify this widget so we must collect states in one place + if ( reset_button_is_active ) + { + // user has perms to press reset button and it is active + if ( user_can_press_reset ) + { + childSetEnabled( "current_url_reset_btn", true ); + } + // user does not has perms to press reset button and it is active + else + { + childSetEnabled( "current_url_reset_btn", false ); + }; + } + else + // reset button is inactive so we just slam it to off - other states don't matter + { + childSetEnabled( "current_url_reset_btn", false ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::clearValues( void* userdata ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + self->mAltImageEnable ->clear(); + self->mAutoLoop->clear(); + self->mAutoPlay->clear(); + self->mAutoScale->clear(); + self->mAutoZoom ->clear(); + self->mControls->clear(); + self->mCurrentURL->clear(); + self->mFirstClick->clear(); + self->mHeightPixels->clear(); + self->mHomeURL->clear(); + self->mWidthPixels->clear(); + self->mPreviewMedia->unloadMediaSource(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + + //llinfos << "---------------" << llendl; + //llinfos << ll_pretty_print_sd(media_settings) << llendl; + //llinfos << "---------------" << llendl; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::AUTO_LOOP_KEY, self->mAutoLoop, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_PLAY_KEY, self->mAutoPlay, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" }, + { LLMediaEntry::CONTROLS_KEY, self->mControls, "LLComboBox" }, + { LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLLineEditor" }, + { LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" }, + { LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" }, + { LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" }, + { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, + { LLMediaEntry::ALT_IMAGE_ENABLE_KEY, self->mAltImageEnable, "LLCheckBoxCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLLineEditor" ) + { + static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )-> + setText( media_settings[ base_key ].asString() ); + } + else + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + else + if ( data_set[ i ].ctrl_type == "LLComboBox" ) + static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> + setCurrentByIndex( media_settings[ base_key ].asInteger() ); + else + if ( data_set[ i ].ctrl_type == "LLSpinCtrl" ) + static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asInteger() ); + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; + + // interrogates controls and updates widgets as required + self->updateMediaPreview(); + self->updateCurrentURL(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set media control to media URL as required +void LLPanelMediaSettingsGeneral::updateMediaPreview() +{ + if ( mHomeURL->getValue().asString().length() > 0 ) + { + mPreviewMedia->navigateTo( mHomeURL->getValue().asString() ); + } + else + // new home URL will be empty if media is deleted but + // we still need to clean out the preview. + { + mPreviewMedia->unloadMediaSource(); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set current URL +void LLPanelMediaSettingsGeneral::updateCurrentURL() +{ + if( mPreviewMedia ) + { + LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); + if( media_plugin ) + { + // get current URL from plugin and display + std::string current_location = media_plugin->getLocation(); + if ( current_location.length() ) + { + childSetText( "current_url", current_location ); + } + else + // current location may be empty so we need to clear it + { + const std::string empty_string( "" ); + childSetText( "current_url", empty_string ); + }; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +void LLPanelMediaSettingsGeneral::onClose() +{ + if(mPreviewMedia) + { + mPreviewMedia->unloadMediaSource(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata ) +{ + LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; + self->updateMediaPreview(); +} + + +//////////////////////////////////////////////////////////////////////////////// +void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl() +{ + // TODO: reset home URL but need to consider permissions too + //LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::apply( void* userdata ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + + // build LLSD Fragment + LLSD media_data_general; + self->getValues(media_data_general); + + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::ALT_IMAGE_ENABLE_KEY] = mAltImageEnable->getValue(); + fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue(); + fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue(); + fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue(); + fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue(); + fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex(); + // XXX Don't send current URL! + //fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); + fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue(); + fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue(); + fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue(); + fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent ) +{ + mParent = parent; +}; diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h new file mode 100644 index 0000000000..24678a3a07 --- /dev/null +++ b/indra/newview/llpanelmediasettingsgeneral.h @@ -0,0 +1,89 @@ +/** + * @file llpanelmediasettingsgeneral.h + * @brief LLPanelMediaSettingsGeneral class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H +#define LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H + +#include "llpanel.h" + +class LLButton; +class LLCheckBoxCtrl; +class LLComboBox; +class LLLineEditor; +class LLSpinCtrl; +class LLTextureCtrl; +class LLMediaCtrl; +class LLFloaterMediaSettings; + +class LLPanelMediaSettingsGeneral : public LLPanel +{ +public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsGeneral(); + ~LLPanelMediaSettingsGeneral(); + + void setParent( LLFloaterMediaSettings* parent ); + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + + void updateMediaPreview(); + void updateCurrentURL(); + + void onClose(); + +protected: + LLFloaterMediaSettings* mParent; + +private: + void onBtnResetCurrentUrl(); + static void onCommitHomeURL(LLUICtrl* ctrl, void *userdata ); + + LLComboBox* mControls; + LLCheckBoxCtrl* mAutoLoop; + LLCheckBoxCtrl* mFirstClick; + LLTextureCtrl* mMediaPreview; + LLCheckBoxCtrl* mAutoZoom; + LLCheckBoxCtrl* mAutoPlay; + LLCheckBoxCtrl* mAutoScale; + LLSpinCtrl* mWidthPixels; + LLSpinCtrl* mHeightPixels; + LLLineEditor* mHomeURL; + LLLineEditor* mCurrentURL; + LLCheckBoxCtrl* mAltImageEnable; + LLMediaCtrl* mPreviewMedia; +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp new file mode 100644 index 0000000000..d6a2677f4b --- /dev/null +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -0,0 +1,223 @@ +/** + * @file llpanelmediasettingspermissions.cpp + * @brief LLPanelMediaSettingsPermissions class implementation + * + * note that "permissions" tab is really "Controls" tab - refs to 'perms' and + * 'permissions' not changed to 'controls' since we don't want to change + * shared files in server code and keeping everything the same seemed best. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmediasettingspermissions.h" +#include "llpanelcontents.h" +#include "llcombobox.h" +#include "llcheckboxctrl.h" +#include "llspinctrl.h" +#include "llurlhistory.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llnamebox.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsPermissions::LLPanelMediaSettingsPermissions() : + mPermsOwnerInteract( 0 ), + mPermsOwnerControl( 0 ), + mPermsGroupName( 0 ), + mPermsGroupInteract( 0 ), + mPermsGroupControl( 0 ), + mPermsWorldInteract( 0 ), + mPermsWorldControl( 0 ) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_permissions.xml"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsPermissions::postBuild() +{ + // connect member vars with UI widgets + mPermsOwnerInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_OWNER_INTERACT_KEY ); + mPermsOwnerControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_OWNER_CONTROL_KEY ); + mPermsGroupInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_GROUP_INTERACT_KEY ); + mPermsGroupControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_GROUP_CONTROL_KEY ); + mPermsWorldInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_ANYONE_INTERACT_KEY ); + mPermsWorldControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_ANYONE_CONTROL_KEY ); + + mPermsGroupName = getChild< LLNameBox >( "perms_group_name" ); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsPermissions::~LLPanelMediaSettingsPermissions() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLPanelMediaSettingsPermissions::draw() +{ + // housekeeping + LLPanel::draw(); + + childSetText("perms_group_name",LLStringUtil::null); + LLUUID group_id; + BOOL groups_identical = LLSelectMgr::getInstance()->selectGetGroup(group_id); + if (groups_identical) + { + if(mPermsGroupName) + { + mPermsGroupName->setNameID(group_id, true); + mPermsGroupName->setEnabled(true); + }; + } + else + { + if(mPermsGroupName) + { + mPermsGroupName->setNameID(LLUUID::null, TRUE); + mPermsGroupName->refresh(LLUUID::null, LLStringUtil::null, LLStringUtil::null, true); + mPermsGroupName->setEnabled(false); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::clearValues( void* userdata ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + self->mPermsOwnerInteract->clear(); + self->mPermsOwnerControl->clear(); + self->mPermsGroupInteract ->clear(); + self->mPermsGroupControl->clear(); + self->mPermsWorldInteract ->clear(); + self->mPermsWorldControl ->clear(); +// mPermsGroupName ->setValue(0); + +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLPanelContents::PERMS_OWNER_INTERACT_KEY, self->mPermsOwnerInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_OWNER_CONTROL_KEY, self->mPermsOwnerControl, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_GROUP_INTERACT_KEY, self->mPermsGroupInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_GROUP_CONTROL_KEY, self->mPermsGroupControl, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_ANYONE_INTERACT_KEY, self->mPermsWorldInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_ANYONE_CONTROL_KEY, self->mPermsWorldControl, "LLCheckBoxCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + // the sense of the checkboxes changed and it made sense + // to just reverse their sense back again here and avoid + // changing server code. + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( ! media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLComboBox" ) + static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> + setCurrentByIndex( media_settings[ base_key ].asInteger() ); + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::apply( void* userdata ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + + // build LLSD Fragment + LLSD media_data_permissions; + self->getValues(media_data_permissions); + + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_permissions ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in ) +{ + // *NOTE: For some reason, gcc does not like these symbol references in the + // expressions below (inside the static_casts). I have NO idea why :(. + // For some reason, assigning them to const temp vars here fixes the link + // error. Bizarre. + const U8 none = LLMediaEntry::PERM_NONE; + const U8 owner = LLMediaEntry::PERM_OWNER; + const U8 group = LLMediaEntry::PERM_GROUP; + const U8 anyone = LLMediaEntry::PERM_ANYONE; + const LLSD::Integer control = static_cast( + (mPermsOwnerControl->getValue() ? none : owner ) | + (mPermsGroupControl->getValue() ? none : group ) | + (mPermsWorldControl->getValue() ? none : anyone )); + const LLSD::Integer interact = static_cast( + (mPermsOwnerInteract->getValue() ? none : owner ) | + (mPermsGroupInteract->getValue() ? none : group ) | + (mPermsWorldInteract->getValue() ? none : anyone )); + fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control; + fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; +} diff --git a/indra/newview/llpanelmediasettingspermissions.h b/indra/newview/llpanelmediasettingspermissions.h new file mode 100644 index 0000000000..ce293e07b9 --- /dev/null +++ b/indra/newview/llpanelmediasettingspermissions.h @@ -0,0 +1,71 @@ +/** + * @file llpanelmediasettingspermissions.h + * @brief LLPanelMediaSettingsPermissions class definition + * + * note that "permissions" tab is really "Controls" tab - refs to 'perms' and + * 'permissions' not changed to 'controls' since we don't want to change + * shared files in server code and keeping everything the same seemed best. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H +#define LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLComboBox; +class LLCheckBoxCtrl; +class LLNameBox; + +class LLPanelMediaSettingsPermissions : public LLPanel +{ + public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsPermissions(); + ~LLPanelMediaSettingsPermissions(); + + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + + private: + LLCheckBoxCtrl* mPermsOwnerInteract; + LLCheckBoxCtrl* mPermsOwnerControl; + LLNameBox* mPermsGroupName; + LLCheckBoxCtrl* mPermsGroupInteract; + LLCheckBoxCtrl* mPermsGroupControl; + LLCheckBoxCtrl* mPermsWorldInteract; + LLCheckBoxCtrl* mPermsWorldControl; +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp new file mode 100644 index 0000000000..a4eee82aa9 --- /dev/null +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -0,0 +1,233 @@ +/** + * @file llpanelmediasettingssecurity.cpp + * @brief LLPanelMediaSettingsSecurity class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelcontents.h" +#include "llcheckboxctrl.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llfloaterwhitelistentry.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); + mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); + mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsSecurity::postBuild() +{ + mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); + + childSetAction("whitelist_add", onBtnAdd, this); + childSetAction("whitelist_del", onBtnDel, this); + + setDefaultBtn("whitelist_add"); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::draw() +{ + // housekeeping + LLPanel::draw(); + + // if list is empty, disable DEL button and checkbox to enable use of list + if ( mWhiteListList->isEmpty() ) + { + childSetEnabled( "whitelist_del", false ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); + }; + + // if nothing is selected, disable DEL button + if ( mWhiteListList->getSelectedValue().asString().empty() ) + { + childSetEnabled( "whitelist_del", false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, + { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) + { + // get control + LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); + list->deleteAllItems(); + + // points to list of white list URLs + LLSD url_list = media_settings[ base_key ]; + + // iterate over them and add to scroll list + LLSD::array_iterator iter = url_list.beginArray(); + while( iter != url_list.endArray() ) + { + // TODO: is iter guaranteed to be valid here? + std::string url = *iter; + list->addSimpleElement( url ); + ++iter; + }; + }; + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::clearValues( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + self->mEnableWhiteList->clear(); + self->mWhiteListList->deleteAllItems(); +} +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::apply( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + // build LLSD Fragment + LLSD media_data_security; + self->getValues(media_data_security); + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); + + // iterate over white list and extract items + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + fill_me_in[LLMediaEntry::WHITELIST_KEY].clear(); + while( iter != white_list_items.end() ) + { + std::string white_list_url = (*iter)->getValue().asString(); + fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); + ++iter; + }; +} + + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) +{ + mWhiteListList->addSimpleElement( url ); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) +{ + LLFloaterReg::showInstance("whitelist_entry"); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + self->mWhiteListList->deleteSelectedItems(); +} diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h new file mode 100644 index 0000000000..d77509897d --- /dev/null +++ b/indra/newview/llpanelmediasettingssecurity.h @@ -0,0 +1,64 @@ +/** + * @file llpanelmediasettingssecurity.h + * @brief LLPanelMediaSettingsSecurity class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H +#define LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H + +#include "llpanel.h" + +class LLCheckBoxCtrl; +class LLScrollListCtrl; + +class LLPanelMediaSettingsSecurity : public LLPanel +{ + public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsSecurity(); + ~LLPanelMediaSettingsSecurity(); + + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + void addWhiteListItem(const std::string& url); + + private: + LLCheckBoxCtrl* mEnableWhiteList; + LLScrollListCtrl* mWhiteListList; + + static void onBtnAdd(void*); + static void onBtnDel(void*); +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b25331e439..ae8c9f770b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1721,13 +1721,8 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright) getSelection()->applyToObjects(&sendfunc); } -void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& media_url) +void LLSelectMgr::selectionSetMedia(U8 media_type) { - U8 media_flags = LLTextureEntry::MF_NONE; - if (media_type == LLViewerObject::MEDIA_TYPE_WEB_PAGE) - { - media_flags = LLTextureEntry::MF_WEB_PAGE; - } struct f : public LLSelectedTEFunctor { @@ -1737,33 +1732,72 @@ void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& { if (object->permModify()) { - // update viewer side color in anticipation of update from simulator + // update viewer has media object->setTEMediaFlags(te, mMediaFlags); } return true; } - } setfunc(media_flags); + } setfunc(media_type); getSelection()->applyToTEs(&setfunc); - - struct g : public LLSelectedObjectFunctor + struct f2 : public LLSelectedObjectFunctor { - U8 media_type; - const std::string& media_url ; - g(U8 a, const std::string& b) : media_type(a), media_url(b) {} virtual bool apply(LLViewerObject* object) { if (object->permModify()) { object->sendTEUpdate(); - object->setMediaType(media_type); - object->setMediaURL(media_url); } return true; } - } sendfunc(media_type, media_url); - getSelection()->applyToObjects(&sendfunc); + } func2; + mSelectedObjects->applyToObjects( &func2 ); } +// This function expects media_data to be a map containing relevant +// media data name/value pairs (e.g. home_url, etc.) +void LLSelectMgr::selectionSetMediaData(const LLSD &media_data) +{ + + struct f : public LLSelectedTEFunctor + { + const LLSD &mMediaData; + f(const LLSD& t) : mMediaData(t) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLVOVolume *vo = dynamic_cast(object); + if (NULL != vo) + { + vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/); + } + } + return true; + } + } setfunc(media_data); + getSelection()->applyToTEs(&setfunc); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + LLVOVolume *vo = dynamic_cast(object); + if (NULL != vo) + { + // Send updated media data FOR THE ENTIRE OBJECT + vo->sendMediaDataUpdate(); + } + } + return true; + } + } func2; + getSelection()->applyToObjects(&func2); +} + + + void LLSelectMgr::selectionSetGlow(F32 glow) { struct f1 : public LLSelectedTEFunctor @@ -5057,7 +5091,15 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected) { return; } - mTESelectMask |= 0x1 << te_index; + S32 mask = 0x1 << te_index; + if(selected) + { + mTESelectMask |= mask; + } + else + { + mTESelectMask &= ~mask; + } mLastTESelected = te_index; } @@ -6042,6 +6084,29 @@ bool LLObjectSelection::applyToRootNodes(LLSelectedNodeFunctor *func, bool first return result; } +BOOL LLObjectSelection::isMultipleTESelected() +{ + BOOL te_selected = FALSE; + // ...all faces + for (LLObjectSelection::iterator iter = begin(); + iter != end(); iter++) + { + LLSelectNode* nodep = *iter; + for (S32 i = 0; i < SELECT_MAX_TES; i++) + { + if(nodep->isTESelected(i)) + { + if(te_selected) + { + return TRUE; + } + te_selected = TRUE; + } + } + } + return FALSE; +} + //----------------------------------------------------------------------------- // contains() //----------------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 08c2783746..9e02170d74 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -307,6 +307,7 @@ public: S32 getTECount(); S32 getRootObjectCount(); + BOOL isMultipleTESelected(); BOOL contains(LLViewerObject* object); BOOL contains(LLViewerObject* object, S32 te); @@ -504,7 +505,8 @@ public: void selectionSetTexGen( U8 texgen ); void selectionSetShiny( U8 shiny ); void selectionSetFullbright( U8 fullbright ); - void selectionSetMediaTypeAndURL( U8 media_type, const std::string& media_url ); + void selectionSetMedia( U8 media_type ); + void selectionSetMediaData(const LLSD &media_data); // NOTE: modifies media_data!!! void selectionSetClickAction(U8 action); void selectionSetIncludeInSearch(bool include_in_search); void selectionSetGlow(const F32 glow); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 4e13cb17a2..7bf0d31d94 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -433,6 +433,11 @@ void LLSpatialGroup::clearDrawMap() mDrawMap.clear(); } +BOOL LLSpatialGroup::isRecentlyVisible() const +{ + return (LLDrawable::getCurrentFrame() - (S32)mVisible) < LLDrawable::getMinVisFrameRange() ; +} + BOOL LLSpatialGroup::isVisible() const { return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE; diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 16e8782a8e..64c2a9acbc 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -267,6 +267,7 @@ public: BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE); BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group BOOL isVisible() const; + BOOL isRecentlyVisible() const; void setVisible(); void shift(const LLVector3 &offset); BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax); diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index ceb1358d1c..880d5d5e12 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -67,18 +67,20 @@ LLTool::~LLTool() BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - if (down) + BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + // This behavior was moved here from LLViewerWindow::handleAnyMouseClick, so it can be selectively overridden by LLTool subclasses. + if(down && result) { + // This is necessary to force clicks in the world to cause edit + // boxes that might have keyboard focus to relinquish it, and hence + // cause a commit to update their value. JC gFocusMgr.setKeyboardFocus(NULL); } - - return LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + return result; } - BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask) { if (gDebugClicks) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 5c210c5c28..d5db224143 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -48,6 +48,7 @@ #include "lltooltip.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llmediaentry.h" #include "llmenugl.h" #include "llmutelist.h" #include "llselectmgr.h" @@ -75,8 +76,6 @@ extern void handle_buy(void*); extern BOOL gDebugClicks; -static bool handle_media_click(const LLPickInfo& info); -static bool handle_media_hover(const LLPickInfo& info); static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer objectp); static ECursorType cursor_from_parcel_media(U8 click_action); @@ -90,6 +89,16 @@ LLToolPie::LLToolPie() { } +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +{ + BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + // This override DISABLES the keyboard focus reset that LLTool::handleAnyMouseClick adds. + // LLToolPie will do the right thing in its pick callback. + + return result; +} + BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) { //left mouse down always picks transparent @@ -258,9 +267,9 @@ BOOL LLToolPie::pickLeftMouseDownCallback() } } - if (handle_media_click(mPick)) + if (handleMediaClick(mPick)) { - return FALSE; + return TRUE; } // put focus back "in world" @@ -466,10 +475,7 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE); - - // FIXME: This was in the pluginapi branch, but I don't think it's correct. -// gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - + LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); @@ -484,7 +490,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->setCursor(cursor); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } - else if (handle_media_hover(mHoverPick)) + else if (handleMediaHover(mHoverPick)) { // cursor set by media object lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; @@ -522,6 +528,9 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) { LLViewerObject* obj = mPick.getObject(); + + handleMediaMouseUp(); + U8 click_action = final_click_action(obj); if (click_action != CLICK_ACTION_NONE) { @@ -543,6 +552,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) break; } } + mGrabMouseButtonDown = FALSE; LLToolMgr::getInstance()->clearTransientTool(); gAgent.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on @@ -1038,6 +1048,7 @@ void LLToolPie::stopEditing() void LLToolPie::onMouseCaptureLost() { mMouseOutsideSlop = FALSE; + handleMediaMouseUp(); } @@ -1078,7 +1089,7 @@ static void handle_click_action_play() } } -static bool handle_media_click(const LLPickInfo& pick) +bool LLToolPie::handleMediaClick(const LLPickInfo& pick) { //FIXME: how do we handle object in different parcel than us? LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -1104,22 +1115,25 @@ static bool handle_media_click(const LLPickInfo& pick) // is media playing on this face? const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; + viewer_media_t media_impl = mep ? LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()) : NULL; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); - if (tep - && media_impl.notNull() - && media_impl->hasMedia() - && gSavedSettings.getBOOL("MediaOnAPrimUI")) + if (tep + && mep + && gSavedSettings.getBOOL("MediaOnAPrimUI") + && media_impl.notNull()) { - LLObjectSelectionHandle selection = LLViewerMediaFocus::getInstance()->getSelection(); - if (! selection->contains(pick.getObject(), pick.mObjectFace)) + // LLObjectSelectionHandle selection = /*LLViewerMediaFocus::getInstance()->getSelection()*/ LLSelectMgr::getInstance()->getSelection(); + if (/*! selection->contains(pick.getObject(), pick.mObjectFace)*/ + ! LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) ) { LLViewerMediaFocus::getInstance()->setFocusFace(TRUE, pick.getObject(), pick.mObjectFace, media_impl); } else { - media_impl->mouseDown(pick.mXYCoords.mX, pick.mXYCoords.mY); - media_impl->mouseCapture(); // the mouse-up will happen when capture is lost + media_impl->mouseDown(pick.mUVCoords); + mMediaMouseCaptureID = mep->getMediaID(); + setMouseCapture(TRUE); // This object will send a mouse-up to the media when it loses capture. } return true; @@ -1131,7 +1145,7 @@ static bool handle_media_click(const LLPickInfo& pick) return false; } -static bool handle_media_hover(const LLPickInfo& pick) +bool LLToolPie::handleMediaHover(const LLPickInfo& pick) { //FIXME: how do we handle object in different parcel than us? LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -1156,15 +1170,20 @@ static bool handle_media_hover(const LLPickInfo& pick) // is media playing on this face? const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); - if (tep - && media_impl.notNull() - && media_impl->hasMedia() + const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; + if (mep && gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - if(LLViewerMediaFocus::getInstance()->getFocus()) + { + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + if(LLViewerMediaFocus::getInstance()->getFocus() && media_impl.notNull()) { - media_impl->mouseMove(pick.mXYCoords.mX, pick.mXYCoords.mY); + media_impl->mouseMove(pick.mUVCoords); + + gViewerWindow->setCursor(media_impl->getLastSetCursor()); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); } // Set mouse over flag if unset @@ -1182,6 +1201,28 @@ static bool handle_media_hover(const LLPickInfo& pick) return false; } +bool LLToolPie::handleMediaMouseUp() +{ + bool result = false; + if(mMediaMouseCaptureID.notNull()) + { + // Face media needs to know the mouse went up. + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mMediaMouseCaptureID); + if(media_impl) + { + // This will send a mouseUp event to the plugin using the last known mouse coordinate (from a mouseDown or mouseMove), which is what we want. + media_impl->onMouseCaptureLost(); + } + + mMediaMouseCaptureID.setNull(); + + setMouseCapture(FALSE); + + result = true; + } + + return result; +} static void handle_click_action_open_media(LLPointer objectp) { diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 328653d2b8..f6a67c13b1 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,9 +42,12 @@ class LLObjectSelection; class LLToolPie : public LLTool, public LLSingleton { + LOG_CLASS(LLToolPie); public: LLToolPie( ); + // Virtual functions inherited from LLMouseHandler + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -81,9 +84,15 @@ private: BOOL useClickAction (MASK mask, LLViewerObject* object,LLViewerObject* parent); void showVisualContextMenuEffect(); + + bool handleMediaClick(const LLPickInfo& info); + bool handleMediaHover(const LLPickInfo& info); + bool handleMediaMouseUp(); + private: BOOL mGrabMouseButtonDown; BOOL mMouseOutsideSlop; // for this drag, has mouse moved outside slop region + LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; LLPointer mClickActionObject; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 725ed57d20..2f656479f6 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -67,6 +67,7 @@ #include "llfloaterhardwaresettings.h" #include "llfloaterhelpbrowser.h" #include "llfloatermediabrowser.h" +#include "llfloatermediasettings.h" #include "llfloaterhud.h" #include "llfloaterimagepreview.h" #include "llimfloater.h" @@ -105,6 +106,7 @@ #include "llfloaterurldisplay.h" #include "llfloatervoicedevicesettings.h" #include "llfloaterwater.h" +#include "llfloaterwhitelistentry.h" #include "llfloaterwindlight.h" #include "llfloaterworldmap.h" #include "llinspectavatar.h" @@ -178,6 +180,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("media_browser", "floater_media_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -238,6 +241,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); // *NOTE: Please keep these alphabetized for easier merges diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index f033d66c1f..100a34291b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -35,12 +35,14 @@ #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llmimetypes.h" +#include "llmediaentry.h" #include "llviewercontrol.h" #include "llviewertexture.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llversionviewer.h" #include "llviewertexturelist.h" +#include "llvovolume.h" #include "llpluginclassmedia.h" #include "llevent.h" // LLSimpleListener @@ -95,10 +97,10 @@ bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) /////////////////////////////////////////////////////////////////////////////// // -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) { + // Broadcast the event to any observers. observerListType::iterator iter = mObservers.begin(); - while( iter != mObservers.end() ) { LLViewerMediaObserver *self = *iter; @@ -166,55 +168,127 @@ public: }; typedef std::vector impl_list; static impl_list sViewerMediaImplList; +static LLTimer sMediaCreateTimer; +static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; + +////////////////////////////////////////////////////////////////////////////////////////// +static void add_media_impl(LLViewerMediaImpl* media) +{ + sViewerMediaImplList.push_back(media); +} + +////////////////////////////////////////////////////////////////////////////////////////// +static void remove_media_impl(LLViewerMediaImpl* media) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMedia ////////////////////////////////////////////////////////////////////////////////////////// // static -viewer_media_t LLViewerMedia::newMediaImpl(const std::string& media_url, - const LLUUID& texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - std::string mime_type) +viewer_media_t LLViewerMedia::newMediaImpl( + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) { LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); if(media_impl == NULL || texture_id.isNull()) { // Create the media impl - media_impl = new LLViewerMediaImpl(media_url, texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); - sViewerMediaImplList.push_back(media_impl); + media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); } else { media_impl->stop(); media_impl->mTextureId = texture_id; - media_impl->mMediaURL = media_url; media_impl->mMediaWidth = media_width; media_impl->mMediaHeight = media_height; media_impl->mMediaAutoScale = media_auto_scale; media_impl->mMediaLoop = media_loop; - if(! media_url.empty()) - media_impl->navigateTo(media_url, mime_type, true); } + return media_impl; } -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::removeMedia(LLViewerMediaImpl* media) -{ - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); +viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) +{ + // Try to find media with the same media ID + viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); + + bool was_loaded = false; + bool needs_navigate = false; - for(; iter != end; iter++) + if(media_impl) + { + was_loaded = media_impl->hasMedia(); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + media_impl->mMediaAutoScale = media_entry->getAutoScale(); + media_impl->mMediaLoop = media_entry->getAutoLoop(); + media_impl->mMediaWidth = media_entry->getWidthPixels(); + media_impl->mMediaHeight = media_entry->getHeightPixels(); + if (media_impl->mMediaSource) + { + media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); + media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); + media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); + } + + if((was_loaded || media_entry->getAutoPlay()) && !update_from_self) + { + if(!media_entry->getCurrentURL().empty()) + { + needs_navigate = (media_entry->getCurrentURL() != previous_url); + } + else if(!media_entry->getHomeURL().empty()) + { + needs_navigate = (media_entry->getHomeURL() != previous_url); + } + } + } + else { - if(media == *iter) + media_impl = newMediaImpl( + media_entry->getMediaID(), + media_entry->getWidthPixels(), + media_entry->getHeightPixels(), + media_entry->getAutoScale(), + media_entry->getAutoLoop()); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + if(media_entry->getAutoPlay()) { - sViewerMediaImplList.erase(iter); - return; + needs_navigate = true; } } + + if(media_impl && needs_navigate) + { + std::string url = media_entry->getCurrentURL(); + if(url.empty()) + url = media_entry->getHomeURL(); + + media_impl->navigateTo(url, "", true, true); + } + + return media_impl; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -323,6 +397,36 @@ void LLViewerMedia::setVolume(F32 volume) } } +// This is the predicate function used to sort sViewerMediaImplList by priority. +static inline bool compare_impl_interest(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return true; + } + else if(i2->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return false; + } + else if(i1->getUsedInUI() && !i2->getUsedInUI()) + { + // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. + return true; + } + else if(i2->getUsedInUI() && !i1->getUsedInUI()) + { + // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. + return false; + } + else + { + // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. + return (i1->getInterest() > i2->getInterest()); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::updateMedia() @@ -334,32 +438,138 @@ void LLViewerMedia::updateMedia() { LLViewerMediaImpl* pimpl = *iter; pimpl->update(); + pimpl->calculateInterest(); } + + // Sort the static instance list using our interest criteria + std::stable_sort(sViewerMediaImplList.begin(), sViewerMediaImplList.end(), compare_impl_interest); + + // Go through the list again and adjust according to priority. + iter = sViewerMediaImplList.begin(); + end = sViewerMediaImplList.end(); + + F64 total_cpu = 0.0f; + int impl_count_total = 0; + int impl_count_interest_low = 0; + int impl_count_interest_normal = 0; + +#if 0 + LL_DEBUGS("PluginPriority") << "Sorted impls:" << llendl; +#endif + + U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); + U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); + U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); + F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + // Setting max_cpu to 0.0 disables CPU usage checking. + bool check_cpu_usage = (max_cpu != 0.0f); + + // Notes on tweakable params: + // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. + // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + + LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + + if(impl_count_total > (int)max_instances) + { + // Hard limit on the number of instances that will be loaded at one time + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + else if(!pimpl->getVisible()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(pimpl->hasFocus()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIGH; + } + else if(pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + } + else + { + // Look at interest and CPU usage for instances that aren't in any of the above states. + + // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, + // turn it down to low instead of normal. This may downsample for plugins that support it. + bool media_is_small = pimpl->getInterest() < (pimpl->getApproximateTextureInterest() / 4); + + if(pimpl->getInterest() == 0.0f) + { + // This media is completely invisible, due to being outside the view frustrum or out of range. + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(check_cpu_usage && (total_cpu > max_cpu)) + { + // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) + { + // Up to max_normal inworld get normal priority + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) + { + // The next max_low inworld get turned down + new_priority = LLPluginClassMedia::PRIORITY_LOW; + impl_count_interest_low++; + + // Set the low priority size for downsampling to approximately the size the texture is displayed at. + { + F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); + + pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + } + } + else + { + // Any additional impls (up to max_instances) get very infrequent time + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + } + + pimpl->setPriority(new_priority); + +#if 0 + LL_DEBUGS("PluginPriority") << " " << pimpl + << ", setting priority to " << new_priority + << (pimpl->hasFocus()?", HAS FOCUS":"") + << (pimpl->getUsedInUI()?", is UI":"") + << ", cpu " << pimpl->getCPUUsage() + << ", interest " << pimpl->getInterest() + << ", media url " << pimpl->getMediaURL() << llendl; +#endif + + total_cpu += pimpl->getCPUUsage(); + impl_count_total++; + } + + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::cleanupClass() { - // This is no longer necessary, since the list is no longer smart pointers. -#if 0 - while(!sViewerMediaImplList.empty()) - { - sViewerMediaImplList.pop_back(); - } -#endif + // This is no longer necessary, since sViewerMediaImplList is no longer smart pointers. } ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMediaImpl ////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, - const LLUUID& texture_id, +LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - const std::string& mime_type) + U8 media_loop) : mMediaSource( NULL ), mMovieImageHasMips(false), @@ -368,13 +578,30 @@ LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, mMediaHeight(media_height), mMediaAutoScale(media_auto_scale), mMediaLoop(media_loop), - mMediaURL(media_url), - mMimeType(mime_type), mNeedsNewTexture(true), mSuspendUpdates(false), - mVisible(true) + mVisible(true), + mLastSetCursor( UI_CURSOR_ARROW ), + mMediaNavState( MEDIANAVSTATE_NONE ), + mInterest(0.0f), + mUsedInUI(false), + mHasFocus(false), + mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), + mDoNavigateOnLoad(false), + mDoNavigateOnLoadServerRequest(false), + mIsUpdated(false) { - createMediaSource(); + + add_media_impl(this); + + // connect this media_impl to the media texture, creating it if it doesn't exist.0 + // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); + if(media_tex) + { + media_tex->setMediaImpl(); + } + } ////////////////////////////////////////////////////////////////////////////////////////// @@ -386,7 +613,26 @@ LLViewerMediaImpl::~LLViewerMediaImpl() } destroyMediaSource(); - LLViewerMedia::removeMedia(this); + + LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; + + remove_media_impl(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + // Broadcast to observers using the superclass version + LLViewerMediaEventEmitter::emitEvent(plugin, event); + + // If this media is on one or more LLVOVolume objects, tell them about the event as well. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + while(iter != mObjectList.end()) + { + LLVOVolume *self = *iter; + ++iter; + self->mediaEvent(this, plugin, event); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -396,11 +642,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) { if(! initializePlugin(mime_type)) { - LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = mime_type; - LLNotifications::instance().add("NoPlugin", args); - + // This may be the case where the plugin's priority is PRIORITY_UNLOADED return false; } } @@ -412,29 +654,42 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::createMediaSource() { - if(! mMediaURL.empty()) + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) { - navigateTo(mMediaURL, mMimeType, true); + // This media shouldn't be created yet. + return; } - else if(! mMimeType.empty()) + + if(mDoNavigateOnLoad) { - initializeMedia(mMimeType); + if(! mMediaURL.empty()) + { + navigateTo(mMediaURL, mMimeType, false, mDoNavigateOnLoadServerRequest); + } + else if(! mMimeType.empty()) + { + initializeMedia(mMimeType); + } } - } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::destroyMediaSource() { mNeedsNewTexture = true; - if(! mMediaSource) + + // Tell the viewer media texture it's no longer active + LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (oldImage) { - return; + oldImage->setPlaying(FALSE) ; } - // Restore the texture - updateMovieImage(LLUUID::null, false); - delete mMediaSource; - mMediaSource = NULL; + + if(mMediaSource) + { + delete mMediaSource; + mMediaSource = NULL; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -487,6 +742,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } } + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotifications::instance().add("NoPlugin", args); + return NULL; } @@ -506,7 +766,15 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // and unconditionally set the mime type mMimeType = media_type; - LLPluginClassMedia* media_source = newSourceFromMediaType(media_type, this, mMediaWidth, mMediaHeight); + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return false; + } + + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight); if (media_source) { @@ -543,13 +811,11 @@ void LLViewerMediaImpl::play() { if(!initializePlugin(mMimeType)) { - // Plugin failed initialization... should assert or something + // This may be the case where the plugin's priority is PRIORITY_UNLOADED return; } } - // updateMovieImage(mTextureId, true); - mMediaSource->loadURI( mMediaURL ); if(/*mMediaSource->pluginSupportsMediaTime()*/ true) { @@ -606,6 +872,8 @@ void LLViewerMediaImpl::setVolume(F32 volume) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::focus(bool focus) { + mHasFocus = focus; + if (mMediaSource) { // call focus just for the hell of it, even though this apopears to be a nop @@ -620,12 +888,20 @@ void LLViewerMediaImpl::focus(bool focus) } } +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::hasFocus() const +{ + // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. + return mHasFocus; +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(S32 x, S32 y) { scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, 0); @@ -638,6 +914,7 @@ void LLViewerMediaImpl::mouseUp(S32 x, S32 y) scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, 0); @@ -647,15 +924,47 @@ void LLViewerMediaImpl::mouseUp(S32 x, S32 y) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseMove(S32 x, S32 y) { - scaleMouse(&x, &y); + scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0); } } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseDown( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + +void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseUp( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + +void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseMove( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) { @@ -694,6 +1003,10 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateHome() { + mMediaURL = mHomeURL; + mDoNavigateOnLoad = !mMediaURL.empty(); + mDoNavigateOnLoadServerRequest = false; + if(mMediaSource) { mMediaSource->loadURI( mHomeURL ); @@ -701,17 +1014,43 @@ void LLViewerMediaImpl::navigateHome() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) { + if(server_request) + { + setNavState(MEDIANAVSTATE_SERVER_SENT); + } + else + { + setNavState(MEDIANAVSTATE_NONE); + } + + // Always set the current URL. + mMediaURL = url; + + // If the current URL is not null, make the instance do a navigate on load. + mDoNavigateOnLoad = !mMediaURL.empty(); + + // and if this was a server request, the navigate on load will also need to be one. + mDoNavigateOnLoadServerRequest = server_request; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return; + } + if(rediscover_type) { - LLURI uri(url); + LLURI uri(mMediaURL); std::string scheme = uri.scheme(); if(scheme.empty() || "http" == scheme || "https" == scheme) { - LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this)); } else if("data" == scheme || "file" == scheme || "about" == scheme) { @@ -719,7 +1058,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // We use "data" internally for a text/html url for loading the login screen if(initializeMedia("text/html")) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } } else @@ -727,24 +1066,23 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // This catches 'rtsp://' urls if(initializeMedia(scheme)) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } } } else if (mMediaSource) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } else if(initializeMedia(mime_type) && mMediaSource) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } else { LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; return; } - mMediaURL = url; } @@ -806,49 +1144,27 @@ bool LLViewerMediaImpl::canNavigateBack() return result; } - ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) +void LLViewerMediaImpl::update() { - // IF the media image hasn't changed, do nothing - if (mTextureId == uuid) - { - return; - } - // If we have changed media uuid, restore the old one - if (!mTextureId.isNull()) + if(mMediaSource == NULL) { - LLViewerMediaTexture* old_image = LLViewerTextureManager::findMediaTexture( mTextureId ); - if (old_image) + if(mPriority != LLPluginClassMedia::PRIORITY_UNLOADED) { - old_image->setPlaying(FALSE); - LLViewerTexture* original_texture = old_image->getOldTexture(); - if(original_texture) + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) { - old_image->switchToTexture(original_texture); + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; } } } - // If the movie is playing, set the new media image - if (active && !uuid.isNull()) - { - LLViewerMediaTexture* viewerImage = LLViewerTextureManager::findMediaTexture( uuid ); - if( viewerImage ) - { - mTextureId = uuid; - - // Can't use mipmaps for movies because they don't update the full image - mMovieImageHasMips = viewerImage->getUseMipMaps(); - viewerImage->reinit(FALSE); - // FIXME -// viewerImage->mIsMediaTexture = TRUE; - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::update() -{ + if(mMediaSource == NULL) { return; @@ -877,6 +1193,10 @@ void LLViewerMediaImpl::update() if(placeholder_image) { LLRect dirty_rect; + + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + placeholder_image->setPlaying(TRUE); + if(mMediaSource->getDirty(&dirty_rect)) { // Constrain the dirty rect to be inside the texture @@ -930,12 +1250,11 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() if (mNeedsNewTexture || placeholder_image->getUseMipMaps() -// || ! placeholder_image->getType() == LLViewerTexture::MEDIA_TEXTURE || placeholder_image->getWidth() != mMediaSource->getTextureWidth() || placeholder_image->getHeight() != mMediaSource->getTextureHeight()) { - llinfos << "initializing media placeholder" << llendl; - llinfos << "movie image id " << mTextureId << llendl; + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; int texture_width = mMediaSource->getTextureWidth(); int texture_height = mMediaSource->getTextureHeight(); @@ -960,9 +1279,6 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() placeholder_image->createGLTexture(discard_level, raw); - // placeholder_image->setExplicitFormat() - placeholder_image->setUseMipMaps(FALSE); - // MEDIAOPT: set this dynamically on play/stop // FIXME // placeholder_image->mIsMediaTexture = true; @@ -996,11 +1312,6 @@ void LLViewerMediaImpl::setVisible(bool visible) createMediaSource(); } } - - if(mMediaSource) - { - mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); - } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1059,7 +1370,7 @@ bool LLViewerMediaImpl::hasMedia() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event) +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) { switch(event) { @@ -1070,11 +1381,77 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClass LLNotifications::instance().add("MediaPluginFailed", args); } break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; + + std::string cursor = plugin->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; + + if(getNavState() == MEDIANAVSTATE_SERVER_SENT) + { + setNavState(MEDIANAVSTATE_SERVER_BEGUN); + } + else + { + setNavState(MEDIANAVSTATE_BEGUN); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; + setNavState(MEDIANAVSTATE_NONE); + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; + + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } + } + break; + + default: break; } + // Just chain the event to observers. - emitEvent(self, event); + emitEvent(plugin, event); } //////////////////////////////////////////////////////////////////////////////// @@ -1137,6 +1514,146 @@ LLViewerMediaImpl::canPaste() const return FALSE; } +void LLViewerMediaImpl::setUpdated(BOOL updated) +{ + mIsUpdated = updated ; +} + +BOOL LLViewerMediaImpl::isUpdated() +{ + return mIsUpdated ; +} + +void LLViewerMediaImpl::calculateInterest() +{ + LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); + + if(texture != NULL) + { + mInterest = texture->getMaxVirtualSize(); + } + else + { + // I don't think this case should ever be hit. + LL_WARNS("Plugin") << "no texture!" << LL_ENDL; + mInterest = 0.0f; + } +} + +F64 LLViewerMediaImpl::getApproximateTextureInterest() +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); + } + + return result; +} + +void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) +{ + mUsedInUI = used_in_ui; + + // HACK: Force elements used in UI to load right away. + // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. + if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) + { + if(getVisible()) + { + mPriority = LLPluginClassMedia::PRIORITY_NORMAL; + } + else + { + mPriority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + + createMediaSource(); + } +}; + +F64 LLViewerMediaImpl::getCPUUsage() const +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getCPUUsage(); + } + + return result; +} + +void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) +{ + mPriority = priority; + + if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + if(mMediaSource) + { + // Need to unload the media source + destroyMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mPriority); + } + + // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). +} + +void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) +{ + if(mMediaSource) + { + mMediaSource->setLowPrioritySizeLimit(size); + } +} + +void LLViewerMediaImpl::setNavState(EMediaNavState state) +{ + mMediaNavState = state; + + switch (state) + { + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; + } +} + + +void LLViewerMediaImpl::addObject(LLVOVolume* obj) +{ + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + if(*iter == obj) + { + return ; //already in the list. + } + } + + mObjectList.push_back(obj) ; +} + +void LLViewerMediaImpl::removeObject(LLVOVolume* obj) +{ + mObjectList.remove(obj) ; +} + +const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const +{ + return &mObjectList ; +} ////////////////////////////////////////////////////////////////////////////////////////// //static diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 9a61394383..775f72d56f 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -41,9 +41,13 @@ #include "llviewermediaobserver.h" +#include "llpluginclassmedia.h" + class LLViewerMediaImpl; class LLUUID; class LLViewerMediaTexture; +class LLMediaEntry; +class LLVOVolume ; typedef LLPointer viewer_media_t; /////////////////////////////////////////////////////////////////////////////// @@ -55,7 +59,7 @@ public: bool addObserver( LLViewerMediaObserver* subject ); bool remObserver( LLViewerMediaObserver* subject ); - void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); private: typedef std::list< LLViewerMediaObserver* > observerListType; @@ -69,15 +73,13 @@ class LLViewerMedia // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC - static viewer_media_t newMediaImpl(const std::string& media_url, - const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop, - std::string mime_type = "none/none"); + static viewer_media_t newMediaImpl(const LLUUID& texture_id, + S32 media_width = 0, + S32 media_height = 0, + U8 media_auto_scale = false, + U8 media_loop = false); - static void removeMedia(LLViewerMediaImpl* media); + static viewer_media_t updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self); static LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); static std::string getCurrentUserAgent(); static void updateBrowserUserAgent(); @@ -102,15 +104,18 @@ class LLViewerMediaImpl LOG_CLASS(LLViewerMediaImpl); public: - LLViewerMediaImpl(const std::string& media_url, + LLViewerMediaImpl( const LLUUID& texture_id, S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - const std::string& mime_type); + U8 media_loop); ~LLViewerMediaImpl(); + + // Override inherited version from LLViewerMediaEventEmitter + virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); + void createMediaSource(); void destroyMediaSource(); void setMediaType(const std::string& media_type); @@ -126,36 +131,44 @@ public: void seek(F32 time); void setVolume(F32 volume); void focus(bool focus); + // True if the impl has user focus. + bool hasFocus() const; void mouseDown(S32 x, S32 y); void mouseUp(S32 x, S32 y); void mouseMove(S32 x, S32 y); + void mouseDown(const LLVector2& texture_coords); + void mouseUp(const LLVector2& texture_coords); + void mouseMove(const LLVector2& texture_coords); void mouseLeftDoubleClick(S32 x,S32 y ); void mouseCapture(); void navigateHome(); - void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false); + void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false); void navigateStop(); bool handleKeyHere(KEY key, MASK mask); bool handleUnicodeCharHere(llwchar uni_char); bool canNavigateForward(); bool canNavigateBack(); std::string getMediaURL() { return mMediaURL; } - std::string getMediaHomeURL() { return mHomeURL; } + std::string getHomeURL() { return mHomeURL; } + void setHomeURL(const std::string& home_url) { mHomeURL = home_url; }; std::string getMimeType() { return mMimeType; } void scaleMouse(S32 *mouse_x, S32 *mouse_y); void update(); - void updateMovieImage(const LLUUID& image_id, BOOL active); void updateImagesMediaStreams(); LLUUID getMediaTextureID(); void suspendUpdates(bool suspend) { mSuspendUpdates = suspend; }; void setVisible(bool visible); + bool getVisible() const { return mVisible; }; bool isMediaPlaying(); bool isMediaPaused(); bool hasMedia(); + ECursorType getLastSetCursor() { return mLastSetCursor; }; + // utility function to create a ready-to-use media instance from a desired media type. static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height); @@ -191,7 +204,7 @@ public: /*virtual*/ BOOL hasMouseCapture() { return gFocusMgr.getMouseCapture() == this; }; // Inherited from LLPluginClassMediaOwner - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent); + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent); // LLEditMenuHandler overrides /*virtual*/ void cut(); @@ -203,6 +216,45 @@ public: /*virtual*/ void paste(); /*virtual*/ BOOL canPaste() const; + void addObject(LLVOVolume* obj) ; + void removeObject(LLVOVolume* obj) ; + const std::list< LLVOVolume* >* getObjectList() const ; + void setUpdated(BOOL updated) ; + BOOL isUpdated() ; + + // Updates the "interest" value in this object + void calculateInterest(); + F64 getInterest() const { return mInterest; }; + F64 getApproximateTextureInterest(); + + // Mark this object as being used in a UI panel instead of on a prim + // This will be used as part of the interest sorting algorithm. + void setUsedInUI(bool used_in_ui); + bool getUsedInUI() const { return mUsedInUI; }; + + F64 getCPUUsage() const; + + void setPriority(LLPluginClassMedia::EPriority priority); + LLPluginClassMedia::EPriority getPriority() { return mPriority; }; + + void setLowPrioritySizeLimit(int size); + + typedef enum + { + MEDIANAVSTATE_NONE, // State is outside what we need to track for navigation. + MEDIANAVSTATE_BEGUN, // a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed + MEDIANAVSTATE_FIRST_LOCATION_CHANGED, // first LOCATION_CHANGED event after a non-server-directed BEGIN + MEDIANAVSTATE_SERVER_SENT, // server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet + MEDIANAVSTATE_SERVER_BEGUN, // MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed + MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED // first LOCATION_CHANGED event after a server-directed BEGIN + + }EMediaNavState; + + // Returns the current nav state of the media. + // note that this will be updated BEFORE listeners and objects receive media messages + EMediaNavState getNavState() { return mMediaNavState; } + void setNavState(EMediaNavState state); + public: // a single media url with some data and an impl. LLPluginClassMedia* mMediaSource; @@ -220,7 +272,19 @@ public: bool mNeedsNewTexture; bool mSuspendUpdates; bool mVisible; + ECursorType mLastSetCursor; + EMediaNavState mMediaNavState; + F64 mInterest; + bool mUsedInUI; + bool mHasFocus; + LLPluginClassMedia::EPriority mPriority; + bool mDoNavigateOnLoad; + bool mDoNavigateOnLoadServerRequest; + +private: + BOOL mIsUpdated ; + std::list< LLVOVolume* > mObjectList ; private: LLViewerMediaTexture *updatePlaceholderImage(); diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index e7576d5c76..f9377ab37b 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -47,6 +47,7 @@ #include "llparcel.h" #include "llviewerparcelmgr.h" #include "llweb.h" +#include "llmediaentry.h" // // LLViewerMediaFocus // @@ -91,14 +92,38 @@ void LLViewerMediaFocus::cleanupClass() void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer objectp, S32 face, viewer_media_t media_impl ) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + if(mMediaImpl.notNull()) + { + mMediaImpl->focus(false); + } + if (b && media_impl.notNull()) { + bool face_auto_zoom = false; mMediaImpl = media_impl; + mMediaImpl->focus(true); + LLSelectMgr::getInstance()->deselectAll(); LLSelectMgr::getInstance()->selectObjectOnly(objectp, face); + if(objectp.notNull()) + { + LLTextureEntry* tep = objectp->getTE(face); + if(! tep->hasMedia()) + { + // Error condition + } + LLMediaEntry* mep = tep->getMediaData(); + face_auto_zoom = mep->getAutoZoom(); + if(! mep->getAutoPlay()) + { + std::string url = mep->getCurrentURL().empty() ? mep->getHomeURL() : mep->getCurrentURL(); + media_impl->navigateTo(url, "", true); + } + } mFocus = LLSelectMgr::getInstance()->getSelection(); - if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom()) + if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom()) { mMediaHUD.get()->resetZoomLevel(); mMediaHUD.get()->nextZoomLevel(); @@ -108,6 +133,7 @@ void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer objectp gFocusMgr.setKeyboardFocus(this); } mObjectID = objectp->getID(); + mObjectFace = face; // LLViewerMedia::addObserver(this, mObjectID); @@ -133,6 +159,8 @@ void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer objectp // and null out the media impl mMediaImpl = NULL; + mObjectID = LLUUID::null; + mObjectFace = 0; } if(mMediaHUD.get()) { @@ -230,6 +258,12 @@ void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl) gHUDView->addChild(media_hud); } mMediaHUD.get()->setMediaImpl(media_impl); + + if(mMediaImpl.notNull() && (mMediaImpl != media_impl)) + { + mMediaImpl->focus(false); + } + mMediaImpl = media_impl; } mMouseOverFlag = b; @@ -356,3 +390,8 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& // Return the aspect ratio. return *width / *height; } + +bool LLViewerMediaFocus::isFocusedOnFace(LLPointer objectp, S32 face) +{ + return objectp->getID() == mObjectID && face == mObjectFace; +} diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index a078d24b6a..2688a8b708 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -72,6 +72,9 @@ public: void setPickInfo(LLPickInfo pick_info) { mPickInfo = pick_info; } F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth); + // TODO: figure out why selection mgr hates me + bool isFocusedOnFace(LLPointer objectp, S32 face); + protected: /*virtual*/ void onFocusReceived(); /*virtual*/ void onFocusLost(); @@ -83,6 +86,7 @@ private: LLPickInfo mPickInfo; LLHandle mMediaHUD; LLUUID mObjectID; + S32 mObjectFace; viewer_media_t mMediaImpl; }; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d3d5f060e1..05011a1568 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -47,6 +47,7 @@ #include "llframetimer.h" #include "llinventory.h" #include "llmaterialtable.h" +#include "llmediadataresponder.h" #include "llmutelist.h" #include "llnamevalue.h" #include "llprimitive.h" @@ -100,6 +101,8 @@ #include "llvowlsky.h" #include "llmanip.h" #include "lltrans.h" +#include "llsdutil.h" +#include "llmediaentry.h" //#define DEBUG_UPDATE_TYPE @@ -470,6 +473,7 @@ void LLViewerObject::cleanupVOClasses() LLVOWater::cleanupClass(); LLVOTree::cleanupClass(); LLVOAvatar::cleanupClass(); + LLVOVolume::cleanupClass(); } // Replaces all name value pairs with data from \n delimited list @@ -700,6 +704,42 @@ void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) } } +U32 LLViewerObject::checkMediaURL(const std::string &media_url) +{ + U32 retval = (U32)0x0; + if (!mMedia && !media_url.empty()) + { + retval |= MEDIA_URL_ADDED; + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mMediaType = LLViewerObject::MEDIA_SET; + mMedia->mPassedWhitelist = FALSE; + } + else if (mMedia) + { + if (media_url.empty()) + { + retval |= MEDIA_URL_REMOVED; + delete mMedia; + mMedia = NULL; + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + */ + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -1045,35 +1085,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, std::string media_url; mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - //if (!media_url.empty()) - //{ - // llinfos << "WEBONPRIM media_url " << media_url << llendl; - //} - if (!mMedia && !media_url.empty()) - { - retval |= MEDIA_URL_ADDED; - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE; - mMedia->mPassedWhitelist = FALSE; - } - else if (mMedia) - { - if (media_url.empty()) - { - retval |= MEDIA_URL_REMOVED; - delete mMedia; - mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) - { - // We just added or changed a web page. - retval |= MEDIA_URL_UPDATED; - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - + retval |= checkMediaURL(media_url); + // // Unpack particle system data // @@ -1456,31 +1469,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText = NULL; } + std::string media_url; if (value & 0x200) { - std::string media_url; dp->unpackString(media_url, "MediaURL"); - if (!mMedia) - { - retval |= MEDIA_URL_ADDED; - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE; - mMedia->mPassedWhitelist = FALSE; - } - else if (mMedia->mMediaURL != media_url) - { - retval |= MEDIA_URL_UPDATED; - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - else if (mMedia) - { - retval |= MEDIA_URL_REMOVED; - delete mMedia; - mMedia = NULL; } + retval |= checkMediaURL(media_url); // // Unpack particle system data @@ -3472,7 +3466,7 @@ U8 LLViewerObject::getMediaType() const } else { - return LLViewerObject::MEDIA_TYPE_NONE; + return LLViewerObject::MEDIA_NONE; } } @@ -3734,16 +3728,13 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost hos } -void LLViewerObject::changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) { - U32 end = getNumTEs() ; - for (U32 face = 0 ; face < end ; face++) + if(index < 0 || index >= getNumTEs()) { - if(old_image == mTEImages[face]) - { - mTEImages[face] = new_image ; - } + return ; } + mTEImages[index] = new_image ; } S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 08e2ec47cd..bec36f9da7 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -158,10 +158,16 @@ public: virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); // Types of media we can associate - enum { MEDIA_TYPE_NONE = 0, MEDIA_TYPE_WEB_PAGE = 1 }; + enum { MEDIA_NONE = 0, MEDIA_SET = 1 }; // Return codes for processUpdateMessage - enum { MEDIA_URL_REMOVED = 0x1, MEDIA_URL_ADDED = 0x2, MEDIA_URL_UPDATED = 0x4, INVALID_UPDATE = 0x80000000 }; + enum { + MEDIA_URL_REMOVED = 0x1, + MEDIA_URL_ADDED = 0x2, + MEDIA_URL_UPDATED = 0x4, + MEDIA_FLAGS_CHANGED = 0x8, + INVALID_UPDATE = 0x80000000 + }; virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -318,7 +324,7 @@ public: /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); /*virtual*/ BOOL setMaterial(const U8 material); virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive - void changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) ; + void changeTEImage(S32 index, LLViewerTexture* new_image) ; LLViewerTexture *getTEImage(const U8 te) const; void fitFaceTexture(const U8 face); @@ -504,6 +510,10 @@ private: ExtraParameter* getExtraParameterEntry(U16 param_type) const; ExtraParameter* getExtraParameterEntryCreate(U16 param_type); bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); + + // This function checks to see if the given media URL has changed its version + // and the update wasn't due to this agent's last action. + U32 checkMediaURL(const std::string &media_url); public: // diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 86d51bfd4b..a3f9c839a0 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -46,6 +46,7 @@ #include "llnotifications.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llviewertexture.h" // Static Variables @@ -219,17 +220,25 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // Delete the old one first so they don't fight over the texture. sMediaImpl->stop(); - sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, - media_width, media_height, media_auto_scale, + sMediaImpl = LLViewerMedia::newMediaImpl( + placeholder_texture_id, + media_width, + media_height, + media_auto_scale, media_loop); + sMediaImpl->navigateTo(media_url); } } else { // There is no media impl, make a new one - sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, - media_width, media_height, media_auto_scale, + sMediaImpl = LLViewerMedia::newMediaImpl( + placeholder_texture_id, + media_width, + media_height, + media_auto_scale, media_loop); + sMediaImpl->navigateTo(media_url); } LLFirstUse::useMedia(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2c68a106c3..7ea55b49e8 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1428,6 +1428,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("EventQueueGet"); capabilityNames.append("FetchInventory"); capabilityNames.append("WebFetchInventoryDescendents"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); capabilityNames.append("FetchLib"); capabilityNames.append("FetchLibDescendents"); capabilityNames.append("GroupProposalBallot"); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index e3d657068f..a2f6b70006 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -62,6 +62,10 @@ #include "llappviewer.h" #include "lltextureatlas.h" #include "lltextureatlasmanager.h" +#include "lltextureentry.h" +#include "llmediaentry.h" +#include "llvovolume.h" +#include "llviewermedia.h" /////////////////////////////////////////////////////////////////////////////// // statics @@ -114,45 +118,18 @@ LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) { - LLViewerMediaTexture::media_map_t::iterator iter = LLViewerMediaTexture::sMediaMap.find(media_id); - if(iter == LLViewerMediaTexture::sMediaMap.end()) - return NULL; - - ((LLViewerMediaTexture*)(iter->second))->getLastReferencedTimer()->reset() ; - return iter->second; + return LLViewerMediaTexture::findMediaTexture(media_id) ; } LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) { - LLViewerMediaTexture* tex = LLViewerTextureManager::findMediaTexture(id) ; + LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id) ; if(!tex) { tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image) ; } - LLViewerTexture* old_tex = tex->getOldTexture() ; - if(!old_tex) - { - //if there is a fetched texture with the same id, replace it by this media texture - old_tex = gTextureList.findImage(id) ; - if(old_tex) - { - tex->setOldTexture(old_tex) ; - } - } - - if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable") && gSavedSettings.getBOOL("AudioStreamingVideo")) - { - if(!tex->isPlaying()) - { - if(old_tex) - { - old_tex->switchToTexture(tex) ; - } - tex->setPlaying(TRUE) ; - } - } - tex->getLastReferencedTimer()->reset() ; + tex->initVirtualSize() ; return tex ; } @@ -303,7 +280,7 @@ void LLViewerTextureManager::cleanup() LLViewerFetchedTexture::sMissingAssetImagep = NULL; LLViewerFetchedTexture::sWhiteImagep = NULL; - LLViewerMediaTexture::sMediaMap.clear() ; + LLViewerMediaTexture::cleanup() ; } //---------------------------------------------------------------------------------------------- @@ -437,6 +414,7 @@ void LLViewerTexture::init(bool firstinit) mTextureState = NO_DELETE ; mDontDiscard = FALSE; mMaxVirtualSize = 0.f; + mNeedsResetMaxVirtualSize = FALSE ; } //virtual @@ -538,33 +516,24 @@ void LLViewerTexture::resetTextureStats(BOOL zero) } } +//virtual +F32 LLViewerTexture::getMaxVirtualSize() +{ + return mMaxVirtualSize ; +} + +//virtual void LLViewerTexture::addFace(LLFace* facep) { mFaceList.push_back(facep) ; } + +//virtual void LLViewerTexture::removeFace(LLFace* facep) { mFaceList.remove(facep) ; } -void LLViewerTexture::switchToTexture(LLViewerTexture* new_texture) -{ - if(this == new_texture) - { - return ; - } - - new_texture->addTextureStats(getMaxVirtualSize()) ; - - for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ) - { - LLFace* facep = *iter++ ; - facep->setTexture(new_texture) ; - facep->getViewerObject()->changeTEImage(this, new_texture) ; - gPipeline.markTextured(facep->getDrawable()); - } -} - void LLViewerTexture::forceActive() { mTextureState = ACTIVE ; @@ -613,7 +582,16 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image { llassert_always(mGLTexturep.notNull()) ; - return mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; + BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; + + if(ret) + { + mFullWidth = mGLTexturep->getCurrentWidth() ; + mFullHeight = mGLTexturep->getCurrentHeight() ; + mComponents = mGLTexturep->getComponents() ; + } + + return ret ; } void LLViewerTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) @@ -2142,18 +2120,59 @@ void LLViewerMediaTexture::updateClass() for(media_map_t::iterator iter = sMediaMap.begin() ; iter != sMediaMap.end(); ) { - LLViewerMediaTexture* mediap = iter->second; - ++iter ; + LLViewerMediaTexture* mediap = iter->second; + // + //Note: delay some time to delete the media textures to stop endlessly creating and immediately removing media texture. + // if(mediap->getNumRefs() == 1 && mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) //one by sMediaMap { - sMediaMap.erase(mediap->getID()) ; + media_map_t::iterator cur = iter++ ; + sMediaMap.erase(cur) ; } + else + { + ++iter ; + } + } +} + +//static +void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id) +{ + LLViewerMediaTexture* media_tex = findMediaTexture(media_id) ; + if(media_tex) + { + media_tex->invalidateMediaImpl() ; } } +//static +void LLViewerMediaTexture::cleanup() +{ + sMediaMap.clear() ; +} + +//static +LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media_id) +{ + media_map_t::iterator iter = sMediaMap.find(media_id); + if(iter == sMediaMap.end()) + { + return NULL; + } + + LLViewerMediaTexture* media_tex = iter->second ; + media_tex->setMediaImpl() ; + media_tex->getLastReferencedTimer()->reset() ; + + return media_tex; +} + LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) - : LLViewerTexture(id, usemipmaps) + : LLViewerTexture(id, usemipmaps), + mMediaImplp(NULL), + mUpdateVirtualSizeTime(0) { sMediaMap.insert(std::make_pair(id, this)); @@ -2165,6 +2184,13 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; mIsPlaying = FALSE ; + + setMediaImpl() ; +} + +//virtual +LLViewerMediaTexture::~LLViewerMediaTexture() +{ } void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) @@ -2172,7 +2198,6 @@ void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) mGLTexturep = NULL ; init(false); mUseMipMaps = usemipmaps ; - mIsPlaying = FALSE ; getLastReferencedTimer()->reset() ; generateGLTexture() ; @@ -2195,14 +2220,336 @@ S8 LLViewerMediaTexture::getType() const return LLViewerTexture::MEDIA_TEXTURE ; } -void LLViewerMediaTexture::setOldTexture(LLViewerTexture* tex) +void LLViewerMediaTexture::invalidateMediaImpl() { - mOldTexturep = tex ; + mMediaImplp = NULL ; } + +void LLViewerMediaTexture::setMediaImpl() +{ + if(!mMediaImplp) + { + mMediaImplp = LLViewerMedia::getMediaImplFromTextureID(mID) ; + } +} + +//return true if all faces to reference to this media texture are found +//Note: mMediaFaceList is valid only for the current instant +// because it does not check the face validity after the current frame. +BOOL LLViewerMediaTexture::findFaces() +{ + mMediaFaceList.clear() ; + + BOOL ret = TRUE ; + + //for parcel media + LLViewerTexture* tex = gTextureList.findImage(mID) ; + if(tex) + { + const ll_face_list_t* face_list = tex->getFaceList() ; + for(ll_face_list_t::const_iterator iter = face_list->begin(); iter != face_list->end(); ++iter) + { + mMediaFaceList.push_back(*iter) ; + } + } -LLViewerTexture* LLViewerMediaTexture::getOldTexture() const + if(!mMediaImplp) + { + return TRUE ; + } + + //for media on a face. + const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList() ; + std::list< LLVOVolume* >::const_iterator iter = obj_list->begin() ; + for(; iter != obj_list->end(); ++iter) + { + LLVOVolume* obj = *iter ; + if(obj->mDrawable.isNull()) + { + ret = FALSE ; + continue ; + } + + S32 face_id = -1 ; + while((face_id = obj->getFaceIndexWithMediaImpl(mMediaImplp, face_id)) > -1) + { + LLFace* facep = obj->mDrawable->getFace(face_id) ; + if(facep) + { + mMediaFaceList.push_back(facep) ; + } + else + { + ret = FALSE ; + } + } + } + + return ret ; +} + +void LLViewerMediaTexture::initVirtualSize() +{ + if(mIsPlaying) + { + return ; + } + + findFaces() ; + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + addTextureStats((*iter)->getVirtualSize()) ; + } +} + +void LLViewerMediaTexture::addMediaToFace(LLFace* facep) +{ + if(!mIsPlaying) + { + return ; //no need to add the face because the media is not in playing. + } + + switchTexture(facep) ; +} + +void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) +{ + if(!mIsPlaying) + { + return ; //no need to remove the face because the media is not in playing. + } + if(!facep) + { + return ; + } + + mIsPlaying = FALSE ; //set to remove the media from the face. + switchTexture(facep) ; + mIsPlaying = TRUE ; //set the flag back. + + if(mFaceList.empty()) //no face referencing to this media + { + stopPlaying() ; + } +} + +//virtual +void LLViewerMediaTexture::addFace(LLFace* facep) +{ + LLViewerTexture::addFace(facep) ; + + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + if(tex) + { + mTextureList.push_back(tex) ;//increase the reference number by one for tex to avoid deleting it. + return ; + } + } + llerrs << "The face does not have a valid texture before media texture." << llendl ; +} + +//virtual +void LLViewerMediaTexture::removeFace(LLFace* facep) +{ + LLViewerTexture::removeFace(facep) ; + + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + if(tex) + { + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + if(*iter == tex) + { + mTextureList.erase(iter) ; //decrease the reference number for tex by one. + return ; + } + } + + // + //we have some trouble here: the texture of the face is changed. + //we need to find the former texture, and remove it from the list to avoid memory leaking. + if(mFaceList.empty()) + { + mTextureList.clear() ; + return ; + } + S32 end = mFaceList.size() ; + std::vector te_list(end) ; + S32 i = 0 ; + for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter) + { + te_list[i++] = (*iter)->getTextureEntry() ;//all textures are in use. + } + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + for(i = 0 ; i < end ; i++) + { + if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use. + { + te_list[i] = NULL ; + break ; + } + } + if(i == end) //no hit for this texture, remove it. + { + mTextureList.erase(iter) ; //decrease the reference number for tex by one. + return ; + } + } + } + } + llerrs << "mTextureList texture reference number is corrupted." << llendl ; +} + +void LLViewerMediaTexture::stopPlaying() +{ + if(mMediaImplp) + { + mMediaImplp->stop() ; + } + mIsPlaying = FALSE ; +} + +void LLViewerMediaTexture::switchTexture(LLFace* facep) +{ + if(facep) + { + //check if another media is playing on this face. + if(facep->getTexture() && facep->getTexture() != this + && facep->getTexture()->getType() == LLViewerTexture::MEDIA_TEXTURE) + { + if(mID == facep->getTexture()->getID()) //this is a parcel media + { + return ; //let the prim media win. + } + } + + if(mIsPlaying) //old textures switch to the media texture + { + facep->switchTexture(this) ; + } + else //switch to old textures. + { + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + facep->switchTexture(tex) ; + } + } + } +} + +void LLViewerMediaTexture::setPlaying(BOOL playing) { - return mOldTexturep ; + if(!mMediaImplp) + { + return ; + } + if(!playing && !mIsPlaying) + { + return ; //media is already off + } + + if(playing == mIsPlaying && !mMediaImplp->isUpdated()) + { + return ; //nothing has changed since last time. + } + + mIsPlaying = playing ; + if(mIsPlaying) //is about to play this media + { + if(findFaces()) + { + //about to update all faces. + mMediaImplp->setUpdated(FALSE) ; + } + + if(mMediaFaceList.empty())//no face pointing to this media + { + stopPlaying() ; + return ; + } + + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + switchTexture(*iter) ; + } + } + else //stop playing this media + { + if(mFaceList.empty()) + { + return ; + } + + ll_face_list_t::iterator cur ; + for(ll_face_list_t::iterator iter = mFaceList.begin(); iter!= mFaceList.end(); ) + { + cur = iter++ ; + switchTexture(*cur) ; //cur could be removed in this function. + } + } + return ; +} + +//virtual +F32 LLViewerMediaTexture::getMaxVirtualSize() +{ + if(LLFrameTimer::getFrameCount() == mUpdateVirtualSizeTime) + { + return mMaxVirtualSize ; + } + mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount() ; + + if(mNeedsResetMaxVirtualSize) + { + mMaxVirtualSize = 0.f ;//reset + mNeedsResetMaxVirtualSize = FALSE ; + } + + if(mIsPlaying) //media is playing + { + if(mFaceList.size() > 0) + { + for(std::list::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter) + { + LLFace* facep = *iter ; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()) ; + } + } + } + } + else //media is not in playing + { + findFaces() ; + + if(!mMediaFaceList.empty()) + { + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + LLFace* facep = *iter ; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()) ; + } + } + } + } + + mNeedsResetMaxVirtualSize = TRUE ; + + return mMaxVirtualSize ; } //---------------------------------------------------------------------------------------------- //end of LLViewerMediaTexture diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 0be1bf81de..596bfea670 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -49,6 +49,7 @@ class LLFace; class LLImageGL ; +class LLViewerObject; class LLViewerTexture; class LLViewerFetchedTexture ; class LLViewerMediaTexture ; @@ -58,7 +59,9 @@ typedef void (*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_ class LLVFile; class LLMessageSystem; - +class LLViewerMediaImpl ; +class LLVOVolume ; + class LLLoadedCallbackEntry { public: @@ -123,6 +126,8 @@ public: BOOST_MAX_LEVEL }; + typedef std::list ll_face_list_t ; + protected: virtual ~LLViewerTexture(); LOG_CLASS(LLViewerTexture); @@ -152,16 +157,17 @@ public: //maxVirtualSize of the texture void addTextureStats(F32 virtual_size) const ; void resetTextureStats(BOOL zero = FALSE); - F32 getMaxVirtualSize()const {return mMaxVirtualSize ;} + virtual F32 getMaxVirtualSize() ; LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;} S32 getFullWidth() const { return mFullWidth; } S32 getFullHeight() const { return mFullHeight; } - void addFace(LLFace* facep) ; - void removeFace(LLFace* facep) ; - + virtual void addFace(LLFace* facep) ; + virtual void removeFace(LLFace* facep) ; + const ll_face_list_t* getFaceList() const {return &mFaceList ;} + void generateGLTexture() ; void destroyGLTexture() ; @@ -206,8 +212,6 @@ public: //end of functions to access LLImageGL //--------------------------------------------------------------------------------------------- - void switchToTexture(LLViewerTexture* new_texture) ; //make all faces pointing to this texture to point to new_texture. - //----------------- /*virtual*/ void setActive() ; void forceActive() ; @@ -233,10 +237,9 @@ protected: BOOL mUseMipMaps ; S8 mComponents; mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need? - + mutable BOOL mNeedsResetMaxVirtualSize ; LLFrameTimer mLastReferencedTimer; - typedef std::list ll_face_list_t ; ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture //GL texture @@ -498,34 +501,61 @@ private: class LLViewerMediaTexture : public LLViewerTexture { protected: - /*virtual*/ ~LLViewerMediaTexture() {} + /*virtual*/ ~LLViewerMediaTexture() ; public: LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; /*virtual*/ S8 getType() const; - void reinit(BOOL usemipmaps = TRUE); BOOL getUseMipMaps() {return mUseMipMaps ; } - void setUseMipMaps(BOOL mipmap) ; + void setUseMipMaps(BOOL mipmap) ; + + void setPlaying(BOOL playing) ; + BOOL isPlaying() const {return mIsPlaying;} + void setMediaImpl() ; - void setOldTexture(LLViewerTexture* tex) ; - LLViewerTexture* getOldTexture() const ; + void initVirtualSize() ; + void invalidateMediaImpl() ; - void setPlaying(BOOL playing) {mIsPlaying = playing ;} - BOOL isPlaying() const {return mIsPlaying;} + void addMediaToFace(LLFace* facep) ; + void removeMediaFromFace(LLFace* facep) ; + + /*virtual*/ void addFace(LLFace* facep) ; + /*virtual*/ void removeFace(LLFace* facep) ; + + /*virtual*/ F32 getMaxVirtualSize() ; +private: + void switchTexture(LLFace* facep) ; + BOOL findFaces() ; + void stopPlaying() ; private: - LLPointer mOldTexturep ; //the texture this media texture replaces. + // + //an instant list, recording all faces referencing or can reference to this media texture. + //NOTE: it is NOT thread safe. + // + std::list< LLFace* > mMediaFaceList ; + + //an instant list keeping all textures which are replaced by the current media texture, + //is only used to avoid the removal of those textures from memory. + std::list< LLPointer > mTextureList ; + + LLViewerMediaImpl* mMediaImplp ; BOOL mIsPlaying ; + U32 mUpdateVirtualSizeTime ; public: static void updateClass() ; + static void cleanup() ; -public: + static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ; + static void removeMediaImplFromTexture(const LLUUID& media_id) ; + +private: typedef std::map< LLUUID, LLPointer > media_map_t ; - static media_map_t sMediaMap ; + static media_map_t sMediaMap ; }; //just an interface class, do not create instance from this class. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 93cb0f0f45..e69779b2dc 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -46,6 +46,8 @@ #include "llvolumemessage.h" #include "material_codes.h" #include "message.h" +#include "llmediadataresponder.h" +#include "llpluginclassmedia.h" // for code in the mediaEvent handler #include "object_flags.h" #include "llagentconstants.h" #include "lldrawable.h" @@ -65,6 +67,10 @@ #include "llworld.h" #include "llselectmgr.h" #include "pipeline.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "llmediadatafetcher.h" +#include "llagent.h" const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; @@ -100,6 +106,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mLODChanged = FALSE; mSculptChanged = FALSE; mSpotLightPriority = 0.f; + + mMediaImplList.resize(getNumTEs()); } LLVOVolume::~LLVOVolume() @@ -108,14 +116,31 @@ LLVOVolume::~LLVOVolume() mTextureAnimp = NULL; delete mVolumeImpl; mVolumeImpl = NULL; + + if(!mMediaImplList.empty()) + { + for(U32 i = 0 ; i < mMediaImplList.size() ; i++) + { + if(mMediaImplList[i].notNull()) + { + mMediaImplList[i]->removeObject(this) ; + } + } + } } // static void LLVOVolume::initClass() { + LLMediaDataFetcher::initClass(); } +// static +void LLVOVolume::cleanupClass() +{ + LLMediaDataFetcher::cleanupClass(); +} U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -123,6 +148,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { LLColor4U color; + const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); @@ -190,10 +216,15 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // // Unpack texture entry data // - if (unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } else { @@ -226,9 +257,16 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl; llwarns << "Bogus TE data in " << getID() << llendl; } - else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + else { - updateTEData(); + if (res2 & teDirtyBits) + { + updateTEData(); + } + if (res2 & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } U32 value = dp->getPassFlags(); @@ -266,14 +304,29 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); - if ( unpackTEMessage(tdp) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result = unpackTEMessage(tdp); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } } } - + if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) { + // If the media changed at all, request new media data + if(mMedia) + { + llinfos << "Media URL: " << mMedia->mMediaURL << llendl; + } + requestMediaDataUpdate(); + } + // ...and clean up any media impls + cleanUpMediaImpls(); + return retval; } @@ -1327,6 +1380,46 @@ BOOL LLVOVolume::isRootEdit() const return TRUE; } +//virtual +void LLVOVolume::setNumTEs(const U8 num_tes) +{ + const U8 old_num_tes = getNumTEs() ; + + if(old_num_tes && old_num_tes < num_tes) //new faces added + { + LLViewerObject::setNumTEs(num_tes) ; + + if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. + { + mMediaImplList.resize(num_tes) ; + const LLTextureEntry* te = getTE(old_num_tes - 1) ; + for(U8 i = old_num_tes; i < num_tes ; i++) + { + setTE(i, *te) ; + mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; + } + mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ; + } + } + else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed + { + U8 end = mMediaImplList.size() ; + for(U8 i = num_tes; i < end ; i++) + { + removeMediaImpl(i) ; + } + mMediaImplList.resize(num_tes) ; + + LLViewerObject::setNumTEs(num_tes) ; + } + else + { + LLViewerObject::setNumTEs(num_tes) ; + } + + return ; +} + void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep) { BOOL changed = (mTEImages[te] != imagep); @@ -1510,6 +1603,321 @@ void LLVOVolume::updateTEData() }*/ } +bool LLVOVolume::hasMedia() const +{ + bool result = false; + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if(te->hasMedia()) + { + result = true; + break; + } + } + return result; +} + +void LLVOVolume::requestMediaDataUpdate() +{ + LLMediaDataFetcher::fetchMedia(this); +} + +void LLVOVolume::cleanUpMediaImpls() +{ + // Iterate through our TEs and remove any Impls that are no longer used + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if( ! te->hasMedia()) + { + // Delete the media IMPL! + removeMediaImpl(i) ; + } + } +} + +void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array) +{ + // media_data_array is an array of media entry maps + + //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; + + LLSD::array_const_iterator iter = media_data_array.beginArray(); + LLSD::array_const_iterator end = media_data_array.endArray(); + U8 texture_index = 0; + for (; iter != end; ++iter, ++texture_index) + { + syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); + } +} + +void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent) +{ + LLTextureEntry *te = getTE(texture_index); + //llinfos << "BEFORE: texture_index = " << texture_index + // << " hasMedia = " << te->hasMedia() << " : " + // << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + + std::string previous_url; + LLMediaEntry* mep = te->getMediaData(); + if(mep) + { + // Save the "current url" from before the update so we can tell if + // it changes. + previous_url = mep->getCurrentURL(); + } + + if (merge) + { + te->mergeIntoMediaData(media_data); + } + else { + // XXX Question: what if the media data is undefined LLSD, but the + // update we got above said that we have media flags?? Here we clobber + // that, assuming the data from the service is more up-to-date. + te->updateMediaData(media_data); + } + + mep = te->getMediaData(); + if(mep) + { + bool update_from_self = false; + if (!ignore_agent) + { + LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); + update_from_self = (updating_agent == gAgent.getID()); + } + viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); + + addMediaImpl(media_impl, texture_index) ; + } + + //llinfos << "AFTER: texture_index = " << texture_index + // << " hasMedia = " << te->hasMedia() << " : " + // << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; +} + +void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + switch(event) + { + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + switch(impl->getNavState()) + { + case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED: + { + // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast. + + bool block_navigation = false; + // FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed + // to deal with multiple face indices. + int face_index = getFaceIndexWithMediaImpl(impl, -1); + std::string new_location = plugin->getLocation(); + + // Find the media entry for this navigate + LLMediaEntry* mep = NULL; + LLTextureEntry *te = getTE(face_index); + if(te) + { + mep = te->getMediaData(); + } + + if(mep) + { + if(!mep->checkCandidateUrl(new_location)) + { + block_navigation = true; + } + } + else + { + llwarns << "Couldn't find media entry!" << llendl; + } + + if(block_navigation) + { + llinfos << "blocking navigate to URI " << new_location << llendl; + + // "bounce back" to the current URL from the media entry + // NOTE: the only way block_navigation can be true is if we found the media entry, so we're guaranteed here that mep is not NULL. + impl->navigateTo(mep->getCurrentURL()); + } + else + { + + llinfos << "broadcasting navigate with URI " << new_location << llendl; + + // Post the navigate to the cap + std::string cap = getRegion()->getCapability("ObjectMediaNavigate"); + if(cap.empty()) + { + // XXX *TODO: deal with no cap! It may happen! (retry?) + LL_WARNS("Media") << "Can't broadcast navigate event -- ObjectMediaNavigate cap is not available" << LL_ENDL; + return; + } + + // If we got here, the cap is available. Index through all faces that have this media and send the navigate message. + LLSD sd; + sd["object_id"] = mID; + sd["current_url"] = new_location; + sd["texture_index"] = face_index; + LLHTTPClient::post(cap, sd, new LLMediaDataResponder("ObjectMediaNavigate", sd, this)); + } + } + break; + + case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: + // This is the first location changed event after the start of a server-directed nav. Don't broadcast it. + llinfos << " NOT broadcasting navigate (server-directed)" << llendl; + break; + + default: + // This is a subsequent location-changed due to a redirect. Don't broadcast. + llinfos << " NOT broadcasting navigate (redirect)" << llendl; + break; + } + } + break; + + default: + break; + } + +} + +void LLVOVolume::sendMediaDataUpdate() const +{ + std::string url = getRegion()->getCapability("ObjectMedia"); + if (!url.empty()) + { + LLSD sd_payload; + sd_payload["verb"] = "UPDATE"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = mID; + LLSD object_media_data; + for (int i=0; i < getNumTEs(); i++) { + LLTextureEntry *texture_entry = getTE(i); + llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia()); + const LLSD &media_data = + (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD(); + object_media_data.append(media_data); + } + sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; + + llinfos << "Sending media data: " << getID() << " " << ll_pretty_print_sd(sd_payload) << llendl; + + LLHTTPClient::post(url, sd_payload, new LLMediaDataResponder("ObjectMedia", sd_payload, this)); + } + // XXX *TODO: deal with no cap! It may happen! (retry?) +} + +void LLVOVolume::removeMediaImpl(S32 texture_index) +{ + if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull()) + { + return ; + } + + //make the face referencing to mMediaImplList[texture_index] to point back to the old texture. + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + if(media_tex) + { + media_tex->removeMediaFromFace(facep) ; + } + } + } + + //check if some other face(s) of this object reference(s)to this media impl. + S32 i ; + S32 end = (S32)mMediaImplList.size() ; + for(i = 0; i < end ; i++) + { + if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index]) + { + break ; + } + } + + if(i == end) //this object does not need this media impl. + { + mMediaImplList[texture_index]->removeObject(this) ; + } + + mMediaImplList[texture_index] = NULL ; + return ; +} + +void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) +{ + if((S32)mMediaImplList.size() < texture_index + 1) + { + mMediaImplList.resize(texture_index + 1) ; + } + + if(mMediaImplList[texture_index].notNull()) + { + if(mMediaImplList[texture_index] == media_impl) + { + return ; + } + + removeMediaImpl(texture_index) ; + } + + mMediaImplList[texture_index] = media_impl; + media_impl->addObject(this) ; + + //add the face to show the media if it is in playing + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + if(media_tex) + { + media_tex->addMediaToFace(facep) ; + } + } + else //the face is not available now, start media on this face later. + { + media_impl->setUpdated(TRUE) ; + } + } + return ; +} + +viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const +{ + if(mMediaImplList.size() > face_id) + { + return mMediaImplList[face_id]; + } + return NULL; +} + +S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id) +{ + S32 end = (S32)mMediaImplList.size() ; + for(S32 face_id = start_face_id + 1; face_id < end; face_id++) + { + if(mMediaImplList[face_id] == media_impl) + { + return face_id ; + } + } + return -1 ; +} + //---------------------------------------------------------------------------- void LLVOVolume::setLightTextureID(LLUUID id) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 1b90219836..9a79b620d5 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -35,6 +35,7 @@ #include "llviewerobject.h" #include "llviewertexture.h" +#include "llviewermedia.h" #include "llframetimer.h" #include "llapr.h" #include "m3math.h" // LLMatrix3 @@ -45,6 +46,8 @@ class LLViewerTextureAnim; class LLDrawPool; class LLSelectNode; +typedef std::vector media_list_t; + enum LLVolumeInterfaceType { INTERFACE_FLEXIBLE = 1, @@ -75,12 +78,14 @@ public: // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME) class LLVOVolume : public LLViewerObject { + LOG_CLASS(LLVOVolume); protected: virtual ~LLVOVolume(); public: static void initClass(); - static void preUpdateGeom(); + static void cleanupClass(); + static void preUpdateGeom(); enum { @@ -153,6 +158,7 @@ public: /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped); + /*virtual*/ void setNumTEs(const U8 num_tes); /*virtual*/ void setTEImage(const U8 te, LLViewerTexture *imagep); /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); @@ -224,13 +230,31 @@ public: BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); - + + void updateObjectMediaData(const LLSD &media_data_duples); + void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); + + // Sync the given media data with the impl and the given te + void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); + + // Send media data update to the simulator. + void sendMediaDataUpdate() const; + + viewer_media_t getMediaImpl(U8 face_id) const; + S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id); + + bool hasMedia() const; + protected: S32 computeLODDetail(F32 distance, F32 radius); BOOL calcLOD(); LLFace* addFace(S32 face_index); void updateTEData(); + void requestMediaDataUpdate(); + void cleanUpMediaImpls(); + void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; + void removeMediaImpl(S32 texture_index) ; public: LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; @@ -251,6 +275,7 @@ private: LLVolumeInterface *mVolumeImpl; LLPointer mSculptTexture; LLPointer mLightTexture; + media_list_t mMediaImplList; // statics public: diff --git a/indra/newview/skins/default/xui/en/floater_media_settings.xml b/indra/newview/skins/default/xui/en/floater_media_settings.xml new file mode 100644 index 0000000000..6ba26f938d --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_media_settings.xml @@ -0,0 +1,20 @@ + + + + + width="134"> + + + + + name="checkbox edit linked parts" > + + + + height="22" > + + Transparency % @@ -2261,7 +2306,7 @@ layout="topleft" left_delta="0" name="glow label" - top_pad="4" + top_pad="2" width="80"> Glow @@ -2281,7 +2326,7 @@ layout="topleft" left_delta="0" name="checkbox fullbright" - top_pad="7" + top_pad="4" width="81" /> Mapping @@ -2439,6 +2484,40 @@ name="weave" value="weave" /> + Repeats per Face @@ -2461,7 +2540,7 @@ left="20" max_val="100" name="TexScaleU" - top_pad="10" + top_pad="6" width="160" /> - - Rotation (degrees) - + - - Repeats Per Meter - + top_delta="25" + width="170" /> + + top_delta="20" + width="170" /> + + - + + + + + Enter a URL or URL pattern to add to the list of allowed domains + + + + + + + + + + Preview + + + + Controls: + + + + Standard + + + Mini + + + + + + + + + + + + + + Note: Parcel Owners & Residents can override this setting + + + + + Size: + + + + X + + + + diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml new file mode 100644 index 0000000000..f11364874a --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml @@ -0,0 +1,49 @@ + + + + + Owner + + + + + + + Group + + + + + + + + Anyone + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_security.xml b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml new file mode 100644 index 0000000000..695e956e41 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml @@ -0,0 +1,56 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 311bf0503a..13b1ec7308 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1728,13 +1728,25 @@ Releases the specified URL, it will no longer be usable llHTTPResponse(key request_id, integer status, string body) Responds to request_id with status and body - + string llGetHTTPHeader(key request_id, string header) Returns the value for header for request_id - - + +llSetPrimMediaParams(integer face, list params) +Set the media params for a particular face on an object. List is a set of name/value pairs (in no particular order). The possible names are below, along with the types of values and what they mean. If media is not already on this object, add it. Params not specified are unchanged, or if new media is added set to the default specified. + + +list llGetPrimMediaParams(integer face, list params) +Get the media params for a particular face on an object, given the desired list of names. Returns a list of values in the order requested. Returns an empty list if no media exists on the face. + + +llClearPrimMedia(integer face) +Clears (deletes) the media and all params from the given face. + + + Set Not Away Set Away Set Not Busy diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index aa6a144247..036fa4923f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -169,6 +169,12 @@ class WindowsManifest(ViewerManifest): # the final exe is complicated because we're not sure where it's coming from, # nor do we have a fixed name for the executable self.path(self.find_existing_file('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe()) + + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), + "slplugin.exe") + # need to get the kdu dll from any of the build directories as well try: self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], @@ -193,11 +199,6 @@ class WindowsManifest(ViewerManifest): self.path("openjpeg.dll") self.end_prefix() - # Plugin host application - if self.prefix(src='../llplugin/slplugin/%s' % self.args['configuration'], dst="llplugin"): - self.path("slplugin.exe") - self.end_prefix() - # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") @@ -487,9 +488,11 @@ class DarwinManifest(ViewerManifest): self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + # plugin launcher + self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") + # plugins if self.prefix(src="", dst="llplugin"): - self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") @@ -680,6 +683,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin") self.path("../linux_updater/linux-updater-stripped", "bin/linux-updater.bin") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") if self.prefix("res-sdl"): self.path("*") # recurse @@ -687,7 +691,6 @@ class Linux_i686Manifest(LinuxManifest): # plugins if self.prefix(src="", dst="bin/llplugin"): - self.path("../llplugin/slplugin/SLPlugin", "SLPlugin") self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so") self.end_prefix("bin/llplugin") -- cgit v1.2.3 From a0a5c8e615869d449bfad94ec9a650aad82cab91 Mon Sep 17 00:00:00 2001 From: Martin Reddy Date: Thu, 1 Oct 2009 09:52:05 +0000 Subject: EXT-1251: strip leading/trailing whitespace from user input in the navigation bar when trying to access if the input is a valid SLURL. --- indra/newview/lllocationinputctrl.cpp | 5 +++-- indra/newview/llnavigationbar.cpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index a6c2435e1e..68dc3854db 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -656,8 +656,9 @@ void LLLocationInputCtrl::changeLocationPresentation() { //change location presentation only if user does not select anything and //human-readable region name is being displayed - if(mTextEntry && !mTextEntry->hasSelection() && - !LLSLURL::isSLURL(mTextEntry->getText())) + std::string text = mTextEntry->getText(); + LLStringUtil::trim(text); + if(mTextEntry && !mTextEntry->hasSelection() && !LLSLURL::isSLURL(text)) { //needs unescaped one mTextEntry->setText(LLAgentUI::buildSLURL(false)); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index b1db51dd26..19fee20740 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -317,6 +317,7 @@ void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) void LLNavigationBar::onLocationSelection() { std::string typed_location = mCmbLocation->getSimple(); + LLStringUtil::trim(typed_location); // Will not teleport to empty location. if (typed_location.empty()) -- cgit v1.2.3 From 090977608d3d4e1d6d26689064910221c66f6084 Mon Sep 17 00:00:00 2001 From: Martin Reddy Date: Thu, 1 Oct 2009 10:23:23 +0000 Subject: DEV-39995: the help browser would crash on open if the media ctrl returned no media plugin for text/html (NULL dereference), which seems to be happening in viewer-2.0.0-3 for me at the moment. Clearly there's not too much to do if we can't display HTML, but this fix will at least stop the help browser from crashing. --- indra/newview/llfloaterhelpbrowser.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index d67b26d36c..6b0b5ed5e0 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -72,7 +72,11 @@ void LLFloaterHelpBrowser::buildURLHistory() LLSD browser_history = LLURLHistory::getURLHistory("browser"); // initialize URL history in the plugin - mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); + LLPluginClassMedia *plugin = mBrowser->getMediaPlugin(); + if (plugin) + { + plugin->initializeUrlHistory(browser_history); + } } void LLFloaterHelpBrowser::onClose() -- cgit v1.2.3 From f05df68656d2abdc38d86cd6746398fa90eb8614 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Thu, 1 Oct 2009 17:44:44 +0000 Subject: merge https://svn.aws.productengine.com/secondlife/export-from-ll/viewer-2-0@1868 https://svn.aws.productengine.com/secondlife/pe/stable-2@1876 -> viewer-2.0.0-3 * Bugs: EXT-1111 EXT-915 EXT-1131 EXT-1200 EXT-1202 EXT-1201 EXT-1205 EXT-1212 EXT-1173 EXT-1229 EXT-1218 EXT-1164 EXT-996 EXT-821 EXT-1030 EXT-1031 EXT-816 * Major Bugs: EXT-1142 (timeout during login due to processing group IMs) * Changes: EXT-1216 (minimize message well) --- indra/llui/CMakeLists.txt | 2 + indra/llui/lldockablefloater.cpp | 18 +- indra/llui/lldockcontrol.cpp | 78 ++-- indra/llui/lldockcontrol.h | 10 +- indra/llui/llflatlistview.cpp | 4 +- indra/llui/lltexteditor.cpp | 43 +++ indra/llui/lltexteditor.h | 10 +- indra/newview/llavatarlist.cpp | 136 ++++--- indra/newview/llavatarlist.h | 25 +- indra/newview/llbottomtray.cpp | 5 +- indra/newview/llchannelmanager.cpp | 54 ++- indra/newview/llchannelmanager.h | 16 +- indra/newview/llchatitemscontainerctrl.cpp | 392 ++++----------------- indra/newview/llchatitemscontainerctrl.h | 86 +---- indra/newview/llchatmsgbox.cpp | 2 +- indra/newview/llchiclet.cpp | 31 +- indra/newview/llchiclet.h | 3 +- indra/newview/llfavoritesbar.cpp | 11 + indra/newview/llfavoritesbar.h | 2 +- indra/newview/llfloaterchatterbox.cpp | 3 +- indra/newview/llgrouplist.cpp | 49 ++- indra/newview/llgrouplist.h | 24 +- indra/newview/llimfloater.cpp | 73 ++-- indra/newview/llimfloater.h | 6 +- indra/newview/llimhandler.cpp | 4 +- indra/newview/llimpanel.cpp | 87 +---- indra/newview/llimpanel.h | 7 +- indra/newview/llimview.cpp | 246 ++++++++++--- indra/newview/llimview.h | 67 +++- indra/newview/llnearbychat.cpp | 29 +- indra/newview/llnearbychat.h | 6 +- indra/newview/llnearbychathandler.cpp | 242 +++++++++++-- indra/newview/llnotificationalerthandler.cpp | 13 +- indra/newview/llnotificationgrouphandler.cpp | 5 +- indra/newview/llnotificationhandler.h | 4 +- indra/newview/llnotificationscripthandler.cpp | 11 +- indra/newview/llnotificationtiphandler.cpp | 5 +- indra/newview/llpanelavatar.cpp | 2 +- indra/newview/llpanelgroup.cpp | 15 +- indra/newview/llpanelgroupgeneral.cpp | 2 + indra/newview/llpanelpeople.cpp | 285 ++++----------- indra/newview/llpanelpeople.h | 27 +- indra/newview/llpanelpick.cpp | 47 ++- indra/newview/llpanelpick.h | 5 + indra/newview/llpanelpicks.cpp | 7 +- indra/newview/llpanelpicks.h | 2 +- indra/newview/llpanelplaces.cpp | 10 +- indra/newview/llpanelteleporthistory.cpp | 8 +- indra/newview/llscreenchannel.cpp | 74 ++-- indra/newview/llscreenchannel.h | 139 +++++--- indra/newview/llsidetray.cpp | 10 +- indra/newview/llstatusbar.cpp | 17 +- indra/newview/llstatusbar.h | 4 +- indra/newview/llsyswellwindow.cpp | 43 ++- indra/newview/llsyswellwindow.h | 6 +- indra/newview/lltoast.cpp | 19 +- indra/newview/lltoast.h | 3 + indra/newview/lltoastpanel.h | 6 + indra/newview/llviewermenu.cpp | 13 + indra/newview/llviewermenu.h | 1 + indra/newview/llviewerwindow.cpp | 6 +- .../skins/default/xui/en/floater_sys_well.xml | 12 +- indra/newview/skins/default/xui/en/menu_viewer.xml | 4 +- .../skins/default/xui/en/panel_bottomtray.xml | 3 - .../default/xui/en/panel_group_info_sidetray.xml | 3 +- .../skins/default/xui/en/panel_nearby_chat_bar.xml | 2 + indra/newview/skins/default/xui/en/panel_notes.xml | 4 +- indra/newview/skins/default/xui/en/panel_picks.xml | 4 +- .../newview/skins/default/xui/en/panel_profile.xml | 6 +- .../skins/default/xui/en/panel_profile_view.xml | 4 +- .../default/xui/en/panel_teleport_history.xml | 2 +- .../skins/default/xui/en/widgets/scroll_list.xml | 6 +- .../default/xui/en/widgets/search_combo_box.xml | 5 +- 73 files changed, 1467 insertions(+), 1148 deletions(-) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index d7d411dee6..0a284f0088 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -85,6 +85,7 @@ set(llui_SOURCE_FILES lltextbox.cpp lltexteditor.cpp lltextparser.cpp + lltransientfloatermgr.cpp lltransutil.cpp lltooltip.cpp llui.cpp @@ -171,6 +172,7 @@ set(llui_HEADER_FILES lltexteditor.h lltextparser.h lltooltip.h + lltransientfloatermgr.h lltransutil.h lluicolortable.h lluiconstants.h diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 93d62fd7c2..4525f0a45b 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -71,9 +71,9 @@ void LLDockableFloater::resetInstance() if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked()) { sInstanceHandle.get()->setVisible(FALSE); - } + } sInstanceHandle = getHandle(); - } + } } void LLDockableFloater::setVisible(BOOL visible) @@ -105,11 +105,11 @@ void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) mDockControl.get()->off(); } - if (!docked && pop_on_undock) - { - // visually pop up a little bit to emphasize the undocking - translate(0, UNDOCK_LEAP_HEIGHT); - } + if (!docked && pop_on_undock) + { + // visually pop up a little bit to emphasize the undocking + translate(0, UNDOCK_LEAP_HEIGHT); + } } else { @@ -126,8 +126,8 @@ void LLDockableFloater::draw() mDockControl.get()->repositionDockable(); if (isDocked()) { - mDockControl.get()->drawToungue(); - } + mDockControl.get()->drawToungue(); + } } LLFloater::draw(); } diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index 0b16b2554c..146c7a969a 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -35,7 +35,7 @@ #include "lldockcontrol.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback) : + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue) { mDockAt = dockAt; @@ -49,13 +49,13 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, off(); } - if (!(get_rect_callback)) + if (!(get_allowed_rect_callback)) { - mGetRectCallback = boost::bind(&LLDockControl::getEnabledRect, this, _1); + mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1); } else { - mGetRectCallback = get_rect_callback; + mGetAllowedRectCallback = get_allowed_rect_callback; } if (dockWidget != NULL) @@ -77,7 +77,7 @@ void LLDockControl::setDock(LLView* dockWidget) } } -void LLDockControl::getEnabledRect(LLRect& rect) +void LLDockControl::getAllowedRect(LLRect& rect) { rect = mDockableFloater->getRootView()->getRect(); } @@ -86,7 +86,7 @@ void LLDockControl::repositionDockable() { LLRect dockRect = mDockWidget->calcScreenRect(); LLRect rootRect; - mGetRectCallback(rootRect); + mGetAllowedRectCallback(rootRect); static BOOL prev_visibility = !mDockWidget->getVisible(); // recalculate dockable position if dock position changed, dock visibility changed, @@ -100,7 +100,7 @@ void LLDockControl::repositionDockable() mDockableFloater->setDocked(false); // force off() since dockable may not have dockControll at this time off(); - } + } else { moveDockable(); @@ -123,10 +123,10 @@ bool LLDockControl::isDockVisible() res = mDockWidget->isInVisibleChain(); if (res) { - LLRect dockRect = mDockWidget->calcScreenRect(); + LLRect dockRect = mDockWidget->calcScreenRect(); switch (mDockAt) - { + { case TOP: // check is dock inside parent rect LLRect dockParentRect = @@ -149,25 +149,25 @@ void LLDockControl::moveDockable() // calculate new dockable position LLRect dockRect = mDockWidget->calcScreenRect(); LLRect rootRect; - mGetRectCallback(rootRect); + mGetAllowedRectCallback(rootRect); - LLRect dockableRect = mDockableFloater->calcScreenRect(); - S32 x = 0; - S32 y = 0; - switch (mDockAt) - { - case TOP: - x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + LLRect dockableRect = mDockableFloater->calcScreenRect(); + S32 x = 0; + S32 y = 0; + switch (mDockAt) + { + case TOP: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight(); // check is dockable inside root view rect - if (x < rootRect.mLeft) - { - x = rootRect.mLeft; - } - if (x + dockableRect.getWidth() > rootRect.mRight) - { - x = rootRect.mRight - dockableRect.getWidth(); - } + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } // calculate dock tongue position @@ -185,21 +185,21 @@ void LLDockControl::moveDockable() { mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; } - mDockTongueY = dockRect.mTop; + mDockTongueY = dockRect.mTop; - break; - } + break; + } // move dockable - dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), - dockableRect.getHeight()); - LLRect localDocableParentRect; - mDockableFloater->getParent()->screenRectToLocal(dockableRect, - &localDocableParentRect); - mDockableFloater->setRect(localDocableParentRect); + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), + dockableRect.getHeight()); + LLRect localDocableParentRect; + mDockableFloater->getParent()->screenRectToLocal(dockableRect, + &localDocableParentRect); + mDockableFloater->setRect(localDocableParentRect); - mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, - &mDockTongueX, &mDockTongueY); + mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, + &mDockTongueX, &mDockTongueY); } @@ -207,9 +207,9 @@ void LLDockControl::on() { if (isDockVisible()) { - mDockableFloater->setCanDrag(false); - mEnabled = true; - mRecalculateDocablePosition = true; + mDockableFloater->setCanDrag(false); + mEnabled = true; + mRecalculateDocablePosition = true; } } diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 219ddfd092..e8ffcac0ac 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -52,11 +52,11 @@ public: public: // callback for a function getting a rect valid for control's position - typedef boost::function get_rect_callback_t; + typedef boost::function get_allowed_rect_callback_t; LOG_CLASS(LLDockControl); LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback = NULL); + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL); virtual ~LLDockControl(); public: @@ -67,13 +67,13 @@ public: void drawToungue(); bool isDockVisible(); - // gets a rect that bounds possible positions for a dockable control - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for a dockable control (EXT-1111) + void getAllowedRect(LLRect& rect); private: virtual void moveDockable(); private: - get_rect_callback_t mGetRectCallback; + get_allowed_rect_callback_t mGetAllowedRectCallback; bool mEnabled; bool mRecalculateDocablePosition; DocAt mDockAt; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 9fcd386c19..e9df361472 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -39,8 +39,8 @@ static const LLDefaultChildRegistry::Register flat_list_view("flat_list_view"); -const LLSD SELECTED_EVENT = LLSD().insert("selected", true); -const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); +const LLSD SELECTED_EVENT = LLSD().insert("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); static const std::string COMMENT_TEXTBOX = "comment_text"; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 8d5f277b59..39f09b297f 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2001,6 +2001,8 @@ void LLTextEditor::cut() deleteSelection( FALSE ); needsReflow(); + + onKeyStroke(); } BOOL LLTextEditor::canCopy() const @@ -2105,6 +2107,8 @@ void LLTextEditor::pasteHelper(bool is_primary) deselect(); needsReflow(); + + onKeyStroke(); } @@ -2492,6 +2496,8 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) if(text_may_have_changed) { needsReflow(); + + onKeyStroke(); } needsScroll(); } @@ -2534,6 +2540,8 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) deselect(); needsReflow(); + + onKeyStroke(); } return handled; @@ -2588,6 +2596,8 @@ void LLTextEditor::doDelete() setCursorPos(mCursorPos + 1); removeChar(); } + + onKeyStroke(); } needsReflow(); @@ -2634,6 +2644,8 @@ void LLTextEditor::undo() setCursorPos(pos); needsReflow(); + + onKeyStroke(); } BOOL LLTextEditor::canRedo() const @@ -2676,6 +2688,8 @@ void LLTextEditor::redo() setCursorPos(pos); needsReflow(); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() @@ -4402,6 +4416,8 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string, // Update of the preedit should be caused by some key strokes. mKeystrokeTimer.reset(); + + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const @@ -4648,3 +4664,30 @@ void LLInlineViewSegment::linkToDocument(LLTextBase* editor) ed->addDocumentChild(mView); } } + +BOOL LLTextEditor::isDirty() const +{ + if(mReadOnly) + { + return FALSE; + } + + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } +} + +void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) +{ + mKeystrokeSignal.connect(callback); +} + +void LLTextEditor::onKeyStroke() +{ + mKeystrokeSignal(this); +} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 68b8f2c3b1..a04261c4be 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -139,6 +139,10 @@ public: virtual ~LLTextEditor(); + typedef boost::signals2::signal keystroke_signal_t; + + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} // mousehandler overrides @@ -169,7 +173,7 @@ public: virtual void clear(); virtual void setFocus( BOOL b ); virtual BOOL acceptsTextInput() const; - virtual BOOL isDirty() const { return isPristine(); } + virtual BOOL isDirty() const; virtual void setValue(const LLSD& value); // LLEditMenuHandler interface @@ -503,6 +507,8 @@ private: S32 getFirstVisibleLine() const; + void onKeyStroke(); + // // Data // @@ -568,6 +574,8 @@ private: BOOL mHandleEditKeysDirectly; LLCoordGL mLastIMEPosition; // Last position of the IME editor + + keystroke_signal_t mKeystrokeSignal; }; // end class LLTextEditor diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index ee14a2ff86..36f9780ad0 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -41,6 +41,10 @@ static LLDefaultChildRegistry::Register r("avatar_list"); +// Maximum number of avatars that can be added to a list in one pass. +// Used to limit time spent for avatar list update per frame. +static const unsigned ADD_LIMIT = 50; + static bool findInsensitive(std::string haystack, const std::string& needle_upper) { LLStringUtil::toUpper(haystack); @@ -65,6 +69,7 @@ LLAvatarList::LLAvatarList(const Params& p) : LLFlatListView(p) , mOnlineGoFirst(p.online_go_first) , mContextMenu(NULL) +, mDirty(true) // to force initial update { setCommitOnSelectionChange(true); @@ -72,44 +77,40 @@ LLAvatarList::LLAvatarList(const Params& p) setComparator(&NAME_COMPARATOR); } -void LLAvatarList::computeDifference( - const std::vector& vnew_unsorted, - std::vector& vadded, - std::vector& vremoved) +// virtual +void LLAvatarList::draw() { - std::vector vcur; - std::vector vnew = vnew_unsorted; + if (mDirty) + refresh(); - // Convert LLSDs to LLUUIDs. - { - std::vector vcur_values; - getValues(vcur_values); + LLFlatListView::draw(); +} - for (size_t i=0; i::iterator it; - size_t maxsize = llmax(vcur.size(), vnew.size()); - vadded.resize(maxsize); - vremoved.resize(maxsize); - - // what to remove - it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); - vremoved.erase(it, vremoved.end()); - - // what to add - it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); - vadded.erase(it, vadded.end()); +void LLAvatarList::sortByName() +{ + setComparator(&NAME_COMPARATOR); + sort(); } -BOOL LLAvatarList::update(const std::vector& all_buddies, const std::string& name_filter) +////////////////////////////////////////////////////////////////////////// +// PROTECTED SECTION +////////////////////////////////////////////////////////////////////////// + +void LLAvatarList::refresh() { - BOOL have_names = TRUE; - bool have_filter = name_filter != LLStringUtil::null; + bool have_names = TRUE; + bool add_limit_exceeded = false; + bool modified = false; + bool have_filter = !mNameFilter.empty(); // Save selection. std::vector selected_ids; @@ -118,22 +119,36 @@ BOOL LLAvatarList::update(const std::vector& all_buddies, const std::str // Determine what to add and what to remove. std::vector added, removed; - LLAvatarList::computeDifference(all_buddies, added, removed); + LLAvatarList::computeDifference(getIDs(), added, removed); // Handle added items. + unsigned nadded = 0; for (std::vector::const_iterator it=added.begin(); it != added.end(); it++) { std::string name; const LLUUID& buddy_id = *it; - have_names &= gCacheName->getFullName(buddy_id, name); - if (!have_filter || findInsensitive(name, name_filter)) - addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + have_names &= (bool)gCacheName->getFullName(buddy_id, name); + if (!have_filter || findInsensitive(name, mNameFilter)) + { + if (nadded >= ADD_LIMIT) + { + add_limit_exceeded = true; + break; + } + else + { + addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + modified = true; + nadded++; + } + } } // Handle removed items. for (std::vector::const_iterator it=removed.begin(); it != removed.end(); it++) { removeItemByUUID(*it); + modified = true; } // Handle filter. @@ -146,9 +161,12 @@ BOOL LLAvatarList::update(const std::vector& all_buddies, const std::str { std::string name; const LLUUID& buddy_id = it->asUUID(); - have_names &= gCacheName->getFullName(buddy_id, name); - if (!findInsensitive(name, name_filter)) + have_names &= (bool)gCacheName->getFullName(buddy_id, name); + if (!findInsensitive(name, mNameFilter)) + { removeItemByUUID(buddy_id); + modified = true; + } } } @@ -167,18 +185,15 @@ BOOL LLAvatarList::update(const std::vector& all_buddies, const std::str // // Otherwise, if we have no filter then no need to update again // because the items will update their names. - return !have_filter || have_names; -} + bool dirty = add_limit_exceeded || (have_filter && !have_names); + setDirty(dirty); -void LLAvatarList::sortByName() -{ - setComparator(&NAME_COMPARATOR); - sort(); + // Commit if we've added/removed items. + if (modified) + onCommit(); } -////////////////////////////////////////////////////////////////////////// -// PROTECTED SECTION -////////////////////////////////////////////////////////////////////////// + void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) { LLAvatarListItem* item = new LLAvatarListItem(); @@ -194,8 +209,39 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is addItem(item, id, pos); } +void LLAvatarList::computeDifference( + const std::vector& vnew_unsorted, + std::vector& vadded, + std::vector& vremoved) +{ + std::vector vcur; + std::vector vnew = vnew_unsorted; + // Convert LLSDs to LLUUIDs. + { + std::vector vcur_values; + getValues(vcur_values); + for (size_t i=0; i::iterator it; + size_t maxsize = llmax(vcur.size(), vnew.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + // what to remove + it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what to add + it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); + vadded.erase(it, vadded.end()); +} bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 8d79e073d2..ec801645fe 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -37,10 +37,22 @@ #include "llavatarlistitem.h" +/** + * Generic list of avatars. + * + * Updates itself when it's dirty, using optional name filter. + * To initiate update, modify the UUID list and call setDirty(). + * + * @see getIDs() + * @see setDirty() + * @see setNameFilter() + */ class LLAvatarList : public LLFlatListView { LOG_CLASS(LLAvatarList); public: + typedef std::vector uuid_vector_t; + struct Params : public LLInitParam::Block { Optional volume_column_width; @@ -51,14 +63,19 @@ public: LLAvatarList(const Params&); virtual ~LLAvatarList() {} - BOOL update(const std::vector& all_buddies, - const std::string& name_filter = LLStringUtil::null); + virtual void draw(); // from LLView + + void setNameFilter(const std::string& filter); + void setDirty(bool val = true) { mDirty = val; } + uuid_vector_t& getIDs() { return mIDs; } void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; } void sortByName(); protected: + void refresh(); + void addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos = ADD_BOTTOM); void computeDifference( const std::vector& vnew, @@ -68,6 +85,10 @@ protected: private: bool mOnlineGoFirst; + bool mDirty; + + std::string mNameFilter; + uuid_vector_t mIDs; LLAvatarListItem::ContextMenu* mContextMenu; }; diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 46151b469f..8771611b1c 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -133,6 +133,7 @@ LLIMChiclet* LLBottomTray::createIMChiclet(const LLUUID& session_id) case LLIMChiclet::TYPE_IM: return getChicletPanel()->createChiclet(session_id); case LLIMChiclet::TYPE_GROUP: + case LLIMChiclet::TYPE_AD_HOC: return getChicletPanel()->createChiclet(session_id); case LLIMChiclet::TYPE_UNKNOWN: break; @@ -231,7 +232,7 @@ void LLBottomTray::showBottomTrayContextMenu(S32 x, S32 y, MASK mask) mBottomTrayContextMenu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, mBottomTrayContextMenu, x, y); - } + } } void LLBottomTray::showGestureButton(BOOL visible) @@ -243,7 +244,7 @@ void LLBottomTray::showGestureButton(BOOL visible) mGestureCombo->setVisible(visible); if (!visible) - { + { LLFloaterReg::hideFloaterInstance("gestures"); r.mRight -= mGestureCombo->getRect().getWidth(); } diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 7ae9976338..b4b680416c 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -77,7 +77,7 @@ LLScreenChannel* LLChannelManager::createNotificationChannel() p.channel_align = CA_RIGHT; // Getting a Channel for our notifications - return LLChannelManager::getInstance()->getChannel(p); + return dynamic_cast (LLChannelManager::getInstance()->createChannel(p)); } //-------------------------------------------------------------------------- @@ -113,7 +113,7 @@ void LLChannelManager::onLoginCompleted() LLChannelManager::Params p; p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); p.channel_align = CA_RIGHT; - mStartUpChannel = getChannel(p); + mStartUpChannel = createChannel(p); if(!mStartUpChannel) { @@ -147,22 +147,32 @@ void LLChannelManager::onStartUpToastClose() LLScreenChannel::setStartUpToastShown(); // force NEARBY CHAT CHANNEL to repost all toasts if present - LLScreenChannel* nearby_channel = findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); - nearby_channel->loadStoredToastsToChannel(); - nearby_channel->setCanStoreToasts(false); + //LLScreenChannelBase* nearby_channel = findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + //!!!!!!!!!!!!!! + //FIXME + //nearby_channel->loadStoredToastsToChannel(); + //nearby_channel->setCanStoreToasts(false); } //-------------------------------------------------------------------------- -LLScreenChannel* LLChannelManager::getChannel(LLChannelManager::Params& p) + +LLScreenChannelBase* LLChannelManager::addChannel(LLScreenChannelBase* channel) { - LLScreenChannel* new_channel = NULL; + if(!channel) + return 0; - new_channel = findChannelByID(p.id); + ChannelElem new_elem; + new_elem.id = channel->getChannelID(); + new_elem.channel = channel; - if(new_channel) - return new_channel; + mChannelList.push_back(new_elem); - new_channel = new LLScreenChannel(p.id); + return channel; +} + +LLScreenChannel* LLChannelManager::createChannel(LLChannelManager::Params& p) +{ + LLScreenChannel* new_channel = new LLScreenChannel(p.id); if(!new_channel) { @@ -172,20 +182,26 @@ LLScreenChannel* LLChannelManager::getChannel(LLChannelManager::Params& p) { new_channel->setToastAlignment(p.toast_align); new_channel->setChannelAlignment(p.channel_align); - new_channel->setDisplayToastsAlways(p.display_toasts_always); - - ChannelElem new_elem; - new_elem.id = p.id; - new_elem.channel = new_channel; + new_channel->setDisplayToastsAlways(p.display_toasts_always); - mChannelList.push_back(new_elem); + addChannel(new_channel); } - return new_channel; } +LLScreenChannelBase* LLChannelManager::getChannel(LLChannelManager::Params& p) +{ + LLScreenChannelBase* new_channel = findChannelByID(p.id); + + if(new_channel) + return new_channel; + + return createChannel(p); + +} + //-------------------------------------------------------------------------- -LLScreenChannel* LLChannelManager::findChannelByID(const LLUUID id) +LLScreenChannelBase* LLChannelManager::findChannelByID(const LLUUID id) { std::vector::iterator it = find(mChannelList.begin(), mChannelList.end(), id); if(it != mChannelList.end()) diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h index 811fa06d2b..b927d369cd 100644 --- a/indra/newview/llchannelmanager.h +++ b/indra/newview/llchannelmanager.h @@ -52,8 +52,8 @@ class LLChannelManager : public LLSingleton public: struct Params { - LLUUID id; - bool display_toasts_always; + LLUUID id; + bool display_toasts_always; EToastAlignment toast_align; EChannelAlignment channel_align; @@ -64,7 +64,7 @@ public: struct ChannelElem { LLUUID id; - LLScreenChannel* channel; + LLScreenChannelBase* channel; ChannelElem() : id(LLUUID("")), channel(NULL) { } @@ -89,19 +89,23 @@ public: void onStartUpToastClose(); // creates a new ScreenChannel according to the given parameters or returns existing if present - LLScreenChannel* getChannel(LLChannelManager::Params& p); + LLScreenChannelBase* getChannel(LLChannelManager::Params& p); + + LLScreenChannelBase* addChannel(LLScreenChannelBase* channel); // returns a channel by its ID - LLScreenChannel* findChannelByID(const LLUUID id); + LLScreenChannelBase* findChannelByID(const LLUUID id); // creator of the Notification channel, that is used in more than one handler - LLScreenChannel* createNotificationChannel(); + LLScreenChannel* createNotificationChannel(); // remove channel methods void removeChannelByID(const LLUUID id); private: + LLScreenChannel* createChannel(LLChannelManager::Params& p); + LLScreenChannel* mStartUpChannel; std::vector mChannelList; }; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 6fb6552f2d..c2d7e0d935 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -44,6 +44,7 @@ #include "llviewercontrol.h" #include "llagentdata.h" +/* static const S32 BORDER_MARGIN = 2; static const S32 PARENT_BORDER_MARGIN = 0; @@ -53,33 +54,27 @@ static const F32 MIN_AUTO_SCROLL_RATE = 120.f; static const F32 MAX_AUTO_SCROLL_RATE = 500.f; static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; -static const S32 msg_left_offset = 30; -static const S32 msg_right_offset = 10; - #define MAX_CHAT_HISTORY 100 +*/ +static const S32 msg_left_offset = 30; +static const S32 msg_right_offset = 10; -static LLDefaultChildRegistry::Register t2("chat_items_container"); - - +//static LLDefaultChildRegistry::Register t2("chat_items_container"); //******************************************************************************************************************* //LLChatItemCtrl //******************************************************************************************************************* -LLChatItemCtrl* LLChatItemCtrl::createInstance() +LLNearbyChatToastPanel* LLNearbyChatToastPanel::createInstance() { - LLChatItemCtrl* item = new LLChatItemCtrl(); + LLNearbyChatToastPanel* item = new LLNearbyChatToastPanel(); LLUICtrlFactory::getInstance()->buildPanel(item, "panel_chat_item.xml"); + item->setFollows(FOLLOWS_NONE); return item; } -void LLChatItemCtrl::draw() -{ - LLPanel::draw(); -} - -void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +void LLNearbyChatToastPanel::reshape (S32 width, S32 height, BOOL called_from_parent ) { LLPanel::reshape(width, height,called_from_parent); @@ -101,13 +96,13 @@ void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) } } -BOOL LLChatItemCtrl::postBuild() +BOOL LLNearbyChatToastPanel::postBuild() { return LLPanel::postBuild(); } -std::string LLChatItemCtrl::appendTime() +std::string LLNearbyChatToastPanel::appendTime() { time_t utc_time; utc_time = time_corrected(); @@ -124,48 +119,63 @@ std::string LLChatItemCtrl::appendTime() -void LLChatItemCtrl::addText (const std::string& message) +void LLNearbyChatToastPanel::addText (const std::string& message) { LLChatMsgBox* msg_text = getChild("msg_text", false); msg_text->addText(message); mMessages.push_back(message); } -void LLChatItemCtrl::setMessage (const LLChat& msg) +void LLNearbyChatToastPanel::init(LLSD& notification) { LLPanel* caption = getChild("msg_caption", false); + mText = notification["message"].asString(); // UTF-8 line of text + mFromName = notification["from"].asString(); // agent or object name + mFromID = notification["from_id"].asUUID(); // agent id or object id + int sType = notification["source"].asInteger(); + mSourceType = (EChatSourceType)sType; + std::string str_sender; - - if(gAgentID != msg.mFromID) - str_sender = msg.mFromName; + if(gAgentID != mFromID) + str_sender = mFromName; else str_sender = LLTrans::getString("You");; caption->getChild("sender_name", false)->setText(str_sender); - std::string tt = appendTime(); - - caption->getChild("msg_time", false)->setText(tt); - - - caption->getChild("avatar_icon", false)->setValue(msg.mFromID); + caption->getChild("msg_time", false)->setText(appendTime()); - mOriginalMessage = msg; LLChatMsgBox* msg_text = getChild("msg_text", false); - msg_text->setText(msg.mText); + msg_text->setText(mText); LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) msg_inspector->setVisible(false); mMessages.clear(); + snapToMessageHeight (); + + mIsDirty = true;//will set Avatar Icon in draw +} + +void LLNearbyChatToastPanel::setMessage (const LLChat& chat_msg) +{ + LLSD notification; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + + init(notification); + } -void LLChatItemCtrl::snapToMessageHeight () +void LLNearbyChatToastPanel::snapToMessageHeight () { LLChatMsgBox* text_box = getChild("msg_text", false); S32 new_height = text_box->getTextPixelHeight(); @@ -184,14 +194,14 @@ void LLChatItemCtrl::snapToMessageHeight () } -void LLChatItemCtrl::setWidth(S32 width) +void LLNearbyChatToastPanel::setWidth(S32 width) { LLChatMsgBox* text_box = getChild("msg_text", false); text_box->reshape(width - msg_left_offset - msg_right_offset,100/*its not magic number, we just need any number*/); LLChatMsgBox* msg_text = getChild("msg_text", false); - if(mOriginalMessage.mText.length()) - msg_text->setText(mOriginalMessage.mText); + if(mText.length()) + msg_text->setText(mText); for(size_t i=0;iaddText(mMessages[i]); @@ -200,25 +210,25 @@ void LLChatItemCtrl::setWidth(S32 width) snapToMessageHeight (); } -void LLChatItemCtrl::onMouseLeave (S32 x, S32 y, MASK mask) +void LLNearbyChatToastPanel::onMouseLeave (S32 x, S32 y, MASK mask) { LLPanel* caption = getChild("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); msg_inspector->setVisible(false); } -void LLChatItemCtrl::onMouseEnter (S32 x, S32 y, MASK mask) +void LLNearbyChatToastPanel::onMouseEnter (S32 x, S32 y, MASK mask) { - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) return; LLPanel* caption = getChild("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); msg_inspector->setVisible(true); } -BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +BOOL LLNearbyChatToastPanel::handleMouseDown (S32 x, S32 y, MASK mask) { - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) return LLPanel::handleMouseDown(x,y,mask); LLPanel* caption = getChild("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); @@ -226,12 +236,16 @@ BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom; if(msg_inspector->pointInView(local_x, local_y)) { - LLFloaterReg::showInstance("inspect_avatar", mOriginalMessage.mFromID); + LLFloaterReg::showInstance("inspect_avatar", mFromID); + } + else + { + LLFloaterReg::showInstance("nearby_chat",LLSD()); } return LLPanel::handleMouseDown(x,y,mask); } -void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) +void LLNearbyChatToastPanel::setHeaderVisibility(EShowItemHeader e) { LLPanel* caption = getChild("msg_caption", false); @@ -243,7 +257,7 @@ void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) } -bool LLChatItemCtrl::canAddText () +bool LLNearbyChatToastPanel::canAddText () { LLChatMsgBox* msg_text = findChild("msg_text"); if(!msg_text) @@ -251,7 +265,7 @@ bool LLChatItemCtrl::canAddText () return msg_text->getTextLinesNum()<10; } -BOOL LLChatItemCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +BOOL LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask) { LLPanel* caption = getChild("msg_caption", false); LLUICtrl* avatar_icon = caption->getChild("avatar_icon", false); @@ -260,296 +274,20 @@ BOOL LLChatItemCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) S32 local_y = y - avatar_icon->getRect().mBottom - caption->getRect().mBottom; //eat message for avatar icon if msg was from object - if(avatar_icon->pointInView(local_x, local_y) && mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(avatar_icon->pointInView(local_x, local_y) && mSourceType != CHAT_SOURCE_AGENT) return TRUE; return LLPanel::handleRightMouseDown(x,y,mask); } - - -//******************************************************************************************************************* -//LLChatItemsContainerCtrl -//******************************************************************************************************************* - -LLChatItemsContainerCtrl::LLChatItemsContainerCtrl(const Params& params):LLPanel(params) -{ - mEShowItemHeader = CHATITEMHEADER_SHOW_BOTH; -} - - -void LLChatItemsContainerCtrl::addMessage(const LLChat& msg) -{ - /* - if(msg.mChatType == CHAT_TYPE_DEBUG_MSG) - return; - */ - if(mItems.size() >= MAX_CHAT_HISTORY) - { - LLChatItemCtrl* item = mItems[0]; - removeChild(item); - delete item; - mItems.erase(mItems.begin()); - } - - - if(mItems.size() > 0 - && msg.mFromID == mItems[mItems.size()-1]->getMessage().mFromID - && (msg.mTime-mItems[mItems.size()-1]->getMessage().mTime)<60 - && mItems[mItems.size()-1]->canAddText() - ) - { - mItems[mItems.size()-1]->addText(msg.mText); - mItems[mItems.size()-1]->snapToMessageHeight(); - } - else - { - LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); - mItems.push_back(item); - addChild(item,0); - item->setWidth(getRect().getWidth() - 16); - item->setMessage(msg); - item->snapToMessageHeight(); - - item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); - - item->setVisible(true); - } - - arrange(getRect().getWidth(),getRect().getHeight()); - updateLayout(getRect().getWidth(),getRect().getHeight()); - scrollToBottom(); -} - -void LLChatItemsContainerCtrl::scrollToBottom () -{ - if(mScrollbar->getVisible()) - { - mScrollbar->setDocPos(mScrollbar->getDocPosMax()); - onScrollPosChangeCallback(0,0); - } -} - -void LLChatItemsContainerCtrl::draw() -{ - LLLocalClipRect clip(getRect()); - LLPanel::draw(); -} - -void LLChatItemsContainerCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) -{ - S32 delta_width = width - getRect().getWidth(); - S32 delta_height = height - getRect().getHeight(); - - if (delta_width || delta_height || sForceReshape) - { - arrange(width, height); - } - - updateBoundingRect(); -} - -void LLChatItemsContainerCtrl::arrange (S32 width, S32 height) +void LLNearbyChatToastPanel::draw() { - S32 delta_width = width - getRect().getWidth(); - if(delta_width)//width changed...too bad. now we need to reformat all items - reformatHistoryScrollItems(width); - - calcRecuiredHeight(); - - show_hide_scrollbar(width,height); - - updateLayout(width,height); -} - -void LLChatItemsContainerCtrl::reformatHistoryScrollItems(S32 width) -{ - for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) - { - (*it)->setWidth(width); - } -} - -S32 LLChatItemsContainerCtrl::calcRecuiredHeight () -{ - S32 rec_height = 0; - - std::vector::iterator it; - for(it=mItems.begin(); it!=mItems.end(); ++it) - { - rec_height += (*it)->getRect().getHeight(); - } - - mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); - - return mInnerRect.getHeight(); -} - - -void LLChatItemsContainerCtrl::updateLayout (S32 width, S32 height) -{ - S32 panel_top = height - BORDER_MARGIN ; - S32 panel_width = width; - if(mScrollbar->getVisible()) - { - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - panel_top+=mScrollbar->getDocPos(); - panel_width-=scrollbar_size; - } - - - //set sizes for first panels and dragbars - for(size_t i=0;igetRect(); - panelSetLeftTopAndSize(mItems[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); - panel_top-=panel_rect.getHeight(); - } -} - -void LLChatItemsContainerCtrl::show_hide_scrollbar (S32 width, S32 height) -{ - calcRecuiredHeight(); - if(getRecuiredHeight() > height ) - showScrollbar(width, height); - else - hideScrollbar(width, height); -} - -void LLChatItemsContainerCtrl::showScrollbar (S32 width, S32 height) -{ - bool was_visible = mScrollbar->getVisible(); - - mScrollbar->setVisible(true); - - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - panelSetLeftTopAndSize(mScrollbar,width-scrollbar_size - ,height-PARENT_BORDER_MARGIN,scrollbar_size,height-2*PARENT_BORDER_MARGIN); - - mScrollbar->setPageSize(height); - mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); - - if(was_visible) - { - S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); - mScrollbar->setDocPos(scroll_pos); - updateLayout(width,height); - return; - } -} - -void LLChatItemsContainerCtrl::hideScrollbar (S32 width, S32 height) -{ - if(mScrollbar->getVisible() == false) - return; - mScrollbar->setVisible(false); - - mScrollbar->setDocPos(0); - - if(mItems.size()>0) - { - S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel - S32 diff = panel_top - mItems[0]->getRect().mTop; - shiftPanels(diff); - } -} - -//--------------------------------------------------------------------------------- -void LLChatItemsContainerCtrl::panelSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) -{ - if(!panel) - return; - LLRect panel_rect = panel->getRect(); - panel_rect.setLeftTopAndSize( left, top, width, height); - panel->reshape( width, height, 1); - panel->setRect(panel_rect); -} - -void LLChatItemsContainerCtrl::panelShiftVertical(LLView* panel,S32 delta) -{ - if(!panel) - return; - panel->translate(0,delta); -} - -void LLChatItemsContainerCtrl::shiftPanels(S32 delta) -{ - //Arrange panels - for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) - { - panelShiftVertical((*it),delta); - } - -} - -//--------------------------------------------------------------------------------- - -void LLChatItemsContainerCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) -{ - updateLayout(getRect().getWidth(),getRect().getHeight()); -} - -BOOL LLChatItemsContainerCtrl::postBuild() -{ - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - LLRect scroll_rect; - scroll_rect.setOriginAndSize( - getRect().getWidth() - scrollbar_size, - 1, - scrollbar_size, - getRect().getHeight() - 1); - - - LLScrollbar::Params sbparams; - sbparams.name("scrollable vertical"); - sbparams.rect(scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(mInnerRect.getHeight()); - sbparams.doc_pos(0); - sbparams.page_size(mInnerRect.getHeight()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.change_callback(boost::bind(&LLChatItemsContainerCtrl::onScrollPosChangeCallback, this, _1, _2)); - - mScrollbar = LLUICtrlFactory::create (sbparams); - LLView::addChild( mScrollbar ); - mScrollbar->setVisible( true ); - mScrollbar->setFollowsRight(); - mScrollbar->setFollowsTop(); - mScrollbar->setFollowsBottom(); - - reformatHistoryScrollItems(getRect().getWidth()); - arrange(getRect().getWidth(),getRect().getHeight()); - - return LLPanel::postBuild(); -} -BOOL LLChatItemsContainerCtrl::handleMouseDown (S32 x, S32 y, MASK mask) -{ - return LLPanel::handleMouseDown(x,y,mask); -} -BOOL LLChatItemsContainerCtrl::handleKeyHere (KEY key, MASK mask) -{ - if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) - return TRUE; - return LLPanel::handleKeyHere(key,mask); -} -BOOL LLChatItemsContainerCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) -{ - if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) - return TRUE; - return false; -} - -void LLChatItemsContainerCtrl::setHeaderVisibility(EShowItemHeader e) -{ - if(e == mEShowItemHeader) - return; - mEShowItemHeader = e; - for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) + if(mIsDirty) { - (*it)->setHeaderVisibility(e); + LLPanel* caption = findChild("msg_caption", false); + if(caption) + caption->getChild("avatar_icon", false)->setValue(mFromID); + mIsDirty = false; } + LLToastPanelBase::draw(); } diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index de16cf9505..8fb045b6d9 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -37,6 +37,7 @@ #include "llscrollbar.h" #include "string" #include "llchat.h" +#include "lltoastpanel.h" typedef enum e_show_item_header { @@ -45,20 +46,18 @@ typedef enum e_show_item_header CHATITEMHEADER_SHOW_BOTH } EShowItemHeader; -class LLChatItemCtrl: public LLPanel +class LLNearbyChatToastPanel: public LLToastPanelBase { protected: - LLChatItemCtrl(){}; + LLNearbyChatToastPanel():mIsDirty(false){}; public: - ~LLChatItemCtrl(){} + ~LLNearbyChatToastPanel(){} - static LLChatItemCtrl* createInstance(); + static LLNearbyChatToastPanel* createInstance(); - void draw(); - - const LLChat& getMessage() const { return mOriginalMessage;} + const LLUUID& getFromID() const { return mFromID;} void addText (const std::string& message); void setMessage (const LLChat& msg); @@ -77,78 +76,27 @@ public: void setHeaderVisibility(EShowItemHeader e); BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); -private: - - std::string appendTime (); - -private: - LLChat mOriginalMessage; - - std::vector mMessages; -}; - -class LLChatItemsContainerCtrl: public LLPanel -{ -public: - struct Params - : public LLInitParam::Block - { - Params(){}; - }; - - LLChatItemsContainerCtrl(const Params& params); - - - ~LLChatItemsContainerCtrl(){} - - void addMessage (const LLChat& msg); - - void draw(); - - void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); - - void onScrollPosChangeCallback(S32, LLScrollbar*); - - virtual BOOL postBuild(); - - BOOL handleMouseDown (S32 x, S32 y, MASK mask); - BOOL handleKeyHere (KEY key, MASK mask); - BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - void scrollToBottom (); - - void setHeaderVisibility(EShowItemHeader e); - EShowItemHeader getHeaderVisibility() const { return mEShowItemHeader;}; + virtual void init(LLSD& data); + virtual void draw(); private: - void reformatHistoryScrollItems(S32 width); - void arrange (S32 width, S32 height); - - S32 calcRecuiredHeight (); - S32 getRecuiredHeight () const { return mInnerRect.getHeight(); } - - void updateLayout (S32 width, S32 height); - - void show_hide_scrollbar (S32 width, S32 height); - - void showScrollbar (S32 width, S32 height); - void hideScrollbar (S32 width, S32 height); - - void panelSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); - void panelShiftVertical (LLView* panel,S32 delta); - void shiftPanels (S32 delta); + + std::string appendTime (); private: - std::vector mItems; + std::string mText; // UTF-8 line of text + std::string mFromName; // agent or object name + LLUUID mFromID; // agent id or object id + EChatSourceType mSourceType; - EShowItemHeader mEShowItemHeader; - LLRect mInnerRect; - LLScrollbar* mScrollbar; + std::vector mMessages; + bool mIsDirty; }; + #endif diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp index e6398dd47a..bd0c36b44a 100644 --- a/indra/newview/llchatmsgbox.cpp +++ b/indra/newview/llchatmsgbox.cpp @@ -102,7 +102,7 @@ void LLChatMsgBox::drawText(S32 x, S32 y, const LLWString &text, const LLColor4 // iterate through each block of text that has been added y -= mLineSpacing; - for (std::vector::iterator it = mSeparatorOffset.begin(); true ;) + for (std::vector::iterator it = mSeparatorOffset.begin(); it != mSeparatorOffset.end() ;) { // display the text for this block S32 num_chars = *it - start; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 20c44d5b11..98e492cada 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -49,6 +49,7 @@ #include "llvoicecontrolpanel.h" #include "llgroupmgr.h" #include "llnotificationmanager.h" +#include "lltransientfloatermgr.h" static LLDefaultChildRegistry::Register t1("chiclet_panel"); static LLDefaultChildRegistry::Register t2("chiclet_talk"); @@ -243,26 +244,36 @@ void LLIMChiclet::draw() LLIMChiclet::EType LLIMChiclet::getIMSessionType(const LLUUID& session_id) { EType type = TYPE_UNKNOWN; - LLFloaterIMPanel* im = NULL; if(session_id.isNull()) return type; - if (!(im = LLIMMgr::getInstance()->findFloaterBySession(session_id))) + EInstantMessage im_type = LLIMModel::getInstance()->getType(session_id); + if (IM_COUNT == im_type) { llassert_always(0 && "IM session not found"); // should never happen return type; } - switch(im->getDialogType()) + switch(im_type) { case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: type = TYPE_IM; break; case IM_SESSION_GROUP_START: case IM_SESSION_INVITE: - type = TYPE_GROUP; + if (gAgent.isInGroup(session_id)) + { + type = TYPE_GROUP; + } + else + { + type = TYPE_AD_HOC; + } break; + case IM_SESSION_CONFERENCE_START: + type = TYPE_AD_HOC; default: break; } @@ -285,6 +296,11 @@ LLIMP2PChiclet::Params::Params() avatar_icon.name("avatar_icon"); avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + + // *NOTE dzaporozhan + // Changed icon height from 25 to 24 to fix ticket EXT-794. + // In some cases(after changing UI scale) 25 pixel height icon was + // drawn incorrectly, i'm not sure why. avatar_icon.rect(LLRect(0, 24, 25, 0)); avatar_icon.mouse_opaque(false); @@ -458,6 +474,11 @@ LLIMGroupChiclet::Params::Params() rect(LLRect(0, 25, 45, 0)); group_icon.name("group_icon"); + + // *NOTE dzaporozhan + // Changed icon height from 25 to 24 to fix ticket EXT-794. + // In some cases(after changing UI scale) 25 pixel height icon was + // drawn incorrectly, i'm not sure why. group_icon.rect(LLRect(0, 24, 25, 0)); unread_notifications.name("unread"); @@ -1164,6 +1185,7 @@ LLTalkButton::LLTalkButton(const Params& p) speak_params.rect(speak_rect); mSpeakBtn = LLUICtrlFactory::create(speak_params); addChild(mSpeakBtn); + LLTransientFloaterMgr::getInstance()->addControlView(mSpeakBtn); mSpeakBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_SpeakBtn, this)); mSpeakBtn->setToggleState(FALSE); @@ -1172,6 +1194,7 @@ LLTalkButton::LLTalkButton(const Params& p) show_params.rect(show_rect); mShowBtn = LLUICtrlFactory::create(show_params); addChild(mShowBtn); + LLTransientFloaterMgr::getInstance()->addControlView(mShowBtn); mShowBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_ShowBtn, this)); mShowBtn->setToggleState(FALSE); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 316348cf1d..ef47b54333 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -275,7 +275,8 @@ public: enum EType { TYPE_UNKNOWN, TYPE_IM, - TYPE_GROUP + TYPE_GROUP, + TYPE_AD_HOC }; /*virtual*/ ~LLIMChiclet() {}; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 6b18984f88..ea947a5565 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -934,6 +934,17 @@ void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S LLMenuGL::showPopup(fav_button, menu, x, y); } +BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL; + if(!handled && !gMenuHolder->hasVisibleMenu()) + { + show_navbar_context_menu(this,x,y); + handled = true; + } + + return handled; +} void copy_slurl_to_clipboard_cb(std::string& slurl) { gClipboard.copyFromString(utf8str_to_wstring(slurl)); diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 0be8de29a9..97117c3b4a 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -62,7 +62,7 @@ public: std::string& tooltip_msg); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); // LLInventoryObserver observer trigger virtual void changed(U32 mask); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index 05ea800d0e..dea656b0e4 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -363,7 +363,8 @@ LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater() { // only LLFloaterIMPanels are called "im_floater" LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)panelp; - if (im_floaterp->getVoiceChannel() == LLVoiceChannel::getCurrentVoiceChannel()) + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(im_floaterp->getSessionID()); + if (voice_channel == LLVoiceChannel::getCurrentVoiceChannel()) { return im_floaterp; } diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index d3b013237b..905857f393 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -73,7 +73,11 @@ LLGroupList::Params::Params() LLGroupList::LLGroupList(const Params& p) : LLFlatListView(p) + , mDirty(true) // to force initial update { + // Listen for agent group changes. + gAgent.addListener(this, "new group"); + mShowIcons = gSavedSettings.getBOOL("GroupListShowIcons"); setCommitOnSelectionChange(true); // TODO: implement context menu @@ -84,17 +88,41 @@ LLGroupList::LLGroupList(const Params& p) setComparator(&GROUP_COMPARATOR); } +LLGroupList::~LLGroupList() +{ + gAgent.removeListener(this); +} + +// virtual +void LLGroupList::draw() +{ + if (mDirty) + refresh(); + + LLFlatListView::draw(); +} + +void LLGroupList::setNameFilter(const std::string& filter) +{ + if (mNameFilter != filter) + { + mNameFilter = filter; + setDirty(); + } +} + static bool findInsensitive(std::string haystack, const std::string& needle_upper) { LLStringUtil::toUpper(haystack); return haystack.find(needle_upper) != std::string::npos; } -BOOL LLGroupList::update(const std::string& name_filter) +void LLGroupList::refresh() { const LLUUID& highlight_id = gAgent.getGroupID(); S32 count = gAgent.mGroups.count(); LLUUID id; + bool have_filter = !mNameFilter.empty(); clear(); @@ -102,7 +130,7 @@ BOOL LLGroupList::update(const std::string& name_filter) { id = gAgent.mGroups.get(i).mID; const LLGroupData& group_data = gAgent.mGroups.get(i); - if (name_filter != LLStringUtil::null && !findInsensitive(group_data.mName, name_filter)) + if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) continue; addNewItem(id, group_data.mName, group_data.mInsigniaID, highlight_id == id, ADD_BOTTOM); } @@ -113,13 +141,14 @@ BOOL LLGroupList::update(const std::string& name_filter) // add "none" to list at top { std::string loc_none = LLTrans::getString("GroupsNone"); - if (name_filter == LLStringUtil::null || findInsensitive(loc_none, name_filter)) + if (have_filter || findInsensitive(loc_none, mNameFilter)) addNewItem(LLUUID::null, loc_none, LLUUID::null, highlight_id.isNull(), ADD_TOP); } selectItemByUUID(highlight_id); - return TRUE; + setDirty(false); + onCommit(); } void LLGroupList::toggleIcons() @@ -158,6 +187,18 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL // setCommentVisible(false); } +// virtual +bool LLGroupList::handleEvent(LLPointer event, const LLSD& userdata) +{ + // Why is "new group" sufficient? + if (event->desc() == "new group") + { + setDirty(); + return true; + } + + return false; +} /************************************************************************/ /* LLGroupListItem implementation */ diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 7708b58de6..9c3ab88901 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -33,10 +33,19 @@ #ifndef LL_LLGROUPLIST_H #define LL_LLGROUPLIST_H +#include "llevent.h" #include "llflatlistview.h" #include "llpanel.h" +#include "llpointer.h" -class LLGroupList: public LLFlatListView +/** + * Auto-updating list of agent groups. + * + * Can use optional group name filter. + * + * @see setNameFilter() + */ +class LLGroupList: public LLFlatListView, public LLOldEvents::LLSimpleListener { LOG_CLASS(LLGroupList); public: @@ -46,14 +55,23 @@ public: }; LLGroupList(const Params& p); - BOOL update(const std::string& name_filter = LLStringUtil::null); + virtual ~LLGroupList(); + + virtual void draw(); // from LLView + + void setNameFilter(const std::string& filter); void toggleIcons(); bool getIconsVisible() const { return mShowIcons; } - + private: + void setDirty(bool val = true) { mDirty = val; } + void refresh(); void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, BOOL is_bold, EAddPosition pos = ADD_BOTTOM); + bool handleEvent(LLPointer event, const LLSD& userdata); // called on agent group list changes bool mShowIcons; + bool mDirty; + std::string mNameFilter; }; class LLButton; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 254e16e1fb..1c144b11b0 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -48,6 +48,7 @@ #include "lltrans.h" #include "llviewertexteditor.h" #include "llviewerwindow.h" +#include "lltransientfloatermgr.h" @@ -62,33 +63,46 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) mInputEditor(NULL), mPositioned(false) { - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); - if(session) + EInstantMessage type = LLIMModel::getInstance()->getType(session_id); + if(IM_COUNT != type) { - mDialog = session->mType; - } + mDialog = type; - if (mDialog == IM_NOTHING_SPECIAL) - { - mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); - } - else - { - mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this); + if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog) + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); + } + else + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this); + } } -// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im_session.xml"); LLUI::getRootView()->setFocusLostCallback(boost::bind(&LLIMFloater::focusChangeCallback, this)); mCloseSignal.connect(boost::bind(&LLIMFloater::onClose, this)); + + LLTransientFloaterMgr::getInstance()->registerTransientFloater(this); } void LLIMFloater::onClose() { LLIMModel::instance().sendLeaveSession(mSessionID, mOtherParticipantUUID); + + //*TODO - move to the IMModel::sendLeaveSession() for the integrity (IB) gIMMgr->removeSession(mSessionID); } +void LLIMFloater::setMinimized(BOOL minimize) +{ + if(!isDocked()) + { + setVisible(!minimize); + } + + LLFloater::setMinimized(minimize); +} + /* static */ void LLIMFloater::newIMCallback(const LLSD& data){ @@ -152,16 +166,17 @@ void LLIMFloater::sendMsg() LLIMFloater::~LLIMFloater() { + LLTransientFloaterMgr::getInstance()->unregisterTransientFloater(this); } //virtual BOOL LLIMFloater::postBuild() { - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); - if(session) + const LLUUID& other_party_id = LLIMModel::getInstance()->getOtherParticipantID(mSessionID); + if (other_party_id.notNull()) { - mOtherParticipantUUID = session->mOtherParticipantID; - mControlPanel->setID(session->mOtherParticipantID); + mOtherParticipantUUID = other_party_id; + mControlPanel->setID(mOtherParticipantUUID); } LLButton* slide_left = getChild("slide_left_btn"); @@ -216,17 +231,6 @@ void* LLIMFloater::createPanelGroupControl(void* userdata) return self->mControlPanel; } - - -void LLIMFloater::focusChangeCallback() -{ - // hide docked floater if user clicked inside in-world area - if (isDocked()) - { - setVisible(false); - } -} - void LLIMFloater::onSlide() { LLPanel* im_control_panel = getChild("panel_im_control_panel"); @@ -271,13 +275,13 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id) } floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(), - LLDockControl::TOP, boost::bind(&LLIMFloater::getEnabledRect, floater, _1))); + LLDockControl::TOP, boost::bind(&LLIMFloater::getAllowedRect, floater, _1))); } return floater; } -void LLIMFloater::getEnabledRect(LLRect& rect) +void LLIMFloater::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRect(); } @@ -285,8 +289,10 @@ void LLIMFloater::getEnabledRect(LLRect& rect) void LLIMFloater::setDocked(bool docked, bool pop_on_undock) { // update notification channel state - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::LLScreenChannel* channel = dynamic_cast + (LLNotificationsUI::LLChannelManager::getInstance()-> + findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + LLDockableFloater::setDocked(docked, pop_on_undock); // update notification channel state @@ -298,8 +304,9 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock) void LLIMFloater::setVisible(BOOL visible) { - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::LLScreenChannel* channel = dynamic_cast + (LLNotificationsUI::LLChannelManager::getInstance()-> + findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); LLDockableFloater::setVisible(visible); // update notification channel state diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 276f38e829..a183212f04 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -57,6 +57,8 @@ public: // LLFloater overrides /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + // override LLFloater's minimization according to EXT-1216 + /*virtual*/ void setMinimized(BOOL minimize); // Make IM conversion visible and update the message history static LLIMFloater* show(const LLUUID& session_id); @@ -90,8 +92,8 @@ private: void onSlide(); static void* createPanelIMControl(void* userdata); static void* createPanelGroupControl(void* userdata); - void focusChangeCallback(); - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111) + void getAllowedRect(LLRect& rect); LLPanelChatControlPanel* mControlPanel; LLUUID mSessionID; diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp index 46067c081f..74971f3fd8 100644 --- a/indra/newview/llimhandler.cpp +++ b/indra/newview/llimhandler.cpp @@ -109,7 +109,9 @@ bool LLIMHandler::processNotification(const LLSD& notify) p.panel = im_box; p.can_be_stored = false; p.on_delete_toast = boost::bind(&LLIMHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager; mNewNotificationSignal(); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index aa2beabf3d..abd3cd4def 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -940,7 +940,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mHistoryEditor(NULL), mSessionUUID(session_id), mSessionLabel(session_label), - mVoiceChannel(NULL), mSessionInitialized(FALSE), mSessionStartMsgPos(0), mOtherParticipantUUID(other_participant_id), @@ -956,7 +955,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mTextIMPossible(TRUE), mProfileButtonEnabled(TRUE), mCallBackEnabled(TRUE), - mSpeakers(NULL), mSpeakerPanel(NULL), mFirstKeystrokeTimer(), mLastKeystrokeTimer() @@ -967,7 +965,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, case IM_SESSION_GROUP_START: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); xml_filename = "floater_instant_message_group.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; case IM_SESSION_INVITE: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); @@ -979,16 +976,13 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, { xml_filename = "floater_instant_message_ad_hoc.xml"; } - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; case IM_SESSION_P2P_INVITE: xml_filename = "floater_instant_message.xml"; - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); break; case IM_SESSION_CONFERENCE_START: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); xml_filename = "floater_instant_message_ad_hoc.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; // just received text from another user case IM_NOTHING_SPECIAL: @@ -998,8 +992,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID); mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); - - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); break; default: llwarns << "Unknown session type" << llendl; @@ -1007,10 +999,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, break; } - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); - // All participants will be added to the list of people we've recently interacted with. - mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); setTitle(mSessionLabel); @@ -1058,33 +1046,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, LLFloaterIMPanel::~LLFloaterIMPanel() { - delete mSpeakers; - mSpeakers = NULL; - - // End the text IM session if necessary - if(gVoiceClient && mOtherParticipantUUID.notNull()) - { - switch(mDialog) - { - case IM_NOTHING_SPECIAL: - case IM_SESSION_P2P_INVITE: - gVoiceClient->endUserIMSession(mOtherParticipantUUID); - break; - - default: - // Appease the compiler - break; - } - } - - //kicks you out of the voice channel if it is currently active - - // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). - mVoiceChannel->deactivate(); - - delete mVoiceChannel; - mVoiceChannel = NULL; - //delete focus lost callback mFocusCallbackConnection.disconnect(); } @@ -1152,7 +1113,8 @@ BOOL LLFloaterIMPanel::postBuild() void* LLFloaterIMPanel::createSpeakersPanel(void* data) { LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data; - floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(floaterp->mSpeakers, TRUE); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(floaterp->mSessionUUID); + floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(speaker_mgr, TRUE); return floaterp->mSpeakerPanel; } @@ -1198,12 +1160,14 @@ void LLFloaterIMPanel::draw() && mCallBackEnabled; // hide/show start call and end call buttons - childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); - childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED); + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); + childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); childSetEnabled("start_call_btn", enable_connect); childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); - LLPointer self_speaker = mSpeakers->findSpeaker(gAgent.getID()); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); + LLPointer self_speaker = speaker_mgr->findSpeaker(gAgent.getID()); if(!mTextIMPossible) { mInputEditor->setEnabled(FALSE); @@ -1227,7 +1191,7 @@ void LLFloaterIMPanel::draw() } // show speakers window when voice first connects - if (mShowSpeakersOnConnect && mVoiceChannel->isActive()) + if (mShowSpeakersOnConnect && voice_channel->isActive()) { childSetVisible("active_speakers_panel", TRUE); mShowSpeakersOnConnect = FALSE; @@ -1263,11 +1227,11 @@ void LLFloaterIMPanel::draw() else { // refresh volume and mute checkbox - childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive()); + childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID)); childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); - childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive()); + childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); } LLFloater::draw(); } @@ -1403,12 +1367,6 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 { mNumUnreadMessages++; } - - if (source != LLUUID::null) - { - mSpeakers->speakerChatted(source); - mSpeakers->setSpeakerTyping(source, FALSE); - } } @@ -1589,7 +1547,7 @@ void LLFloaterIMPanel::onClickStartCall(void* userdata) { LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->mVoiceChannel->activate(); + LLIMModel::getInstance()->getVoiceChannel(self->mSessionUUID)->activate(); } // static @@ -1597,7 +1555,7 @@ void LLFloaterIMPanel::onClickEndCall(void* userdata) { LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->getVoiceChannel()->deactivate(); + LLIMModel::getInstance()->getVoiceChannel(self->mSessionUUID)->deactivate(); } // static @@ -1671,7 +1629,8 @@ void LLFloaterIMPanel::onVisibilityChange(const LLSD& new_visibility) mNumUnreadMessages = 0; } - if (new_visibility.asBoolean() && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED) + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + if (new_visibility.asBoolean() && voice_channel->getState() == LLVoiceChannel::STATE_CONNECTED) LLFloaterReg::showInstance("voice_call", mSessionUUID); else LLFloaterReg::hideInstance("voice_call", mSessionUUID); @@ -1723,11 +1682,6 @@ void LLFloaterIMPanel::sendMsg() mSentTypingState = TRUE; } -void LLFloaterIMPanel::updateSpeakersList(const LLSD& speaker_updates) -{ - mSpeakers->updateSpeakers(speaker_updates); -} - void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) { if ( @@ -1751,15 +1705,9 @@ void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) } } -void LLFloaterIMPanel::setSpeakers(const LLSD& speaker_list) -{ - mSpeakers->setSpeakers(speaker_list); -} - void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) { mSessionUUID = session_id; - mVoiceChannel->updateSessionID(session_id); mSessionInitialized = TRUE; //we assume the history editor hasn't moved at all since @@ -1790,6 +1738,7 @@ void LLFloaterIMPanel::requestAutoConnect() void LLFloaterIMPanel::setTyping(BOOL typing) { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); if (typing) { // Every time you type something, reset this timer @@ -1804,7 +1753,7 @@ void LLFloaterIMPanel::setTyping(BOOL typing) mSentTypingState = FALSE; } - mSpeakers->setSpeakerTyping(gAgent.getID(), TRUE); + speaker_mgr->setSpeakerTyping(gAgent.getID(), TRUE); } else { @@ -1814,7 +1763,7 @@ void LLFloaterIMPanel::setTyping(BOOL typing) sendTypingState(FALSE); mSentTypingState = TRUE; } - mSpeakers->setSpeakerTyping(gAgent.getID(), FALSE); + speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); } mTyping = typing; @@ -1874,7 +1823,7 @@ void LLFloaterIMPanel::removeTypingIndicator(const LLIMInfo* im_info) mHistoryEditor->removeTextFromEnd(chars_to_remove); if (im_info) { - mSpeakers->setSpeakerTyping(im_info->mFromID, FALSE); + LLIMModel::getInstance()->getSpeakerManager(mSessionUUID)->setSpeakerTyping(im_info->mFromID, FALSE); } } } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index fd1134ee5e..fb9b28ad16 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -33,6 +33,7 @@ #ifndef LL_IMPANEL_H #define LL_IMPANEL_H +#include "llimview.h" //for LLIMModel #include "lldockablefloater.h" #include "lllogchat.h" #include "lluuid.h" @@ -245,11 +246,7 @@ public: const LLUUID& getSessionID() const { return mSessionUUID; } const LLUUID& getOtherParticipantID() const { return mOtherParticipantUUID; } - LLIMSpeakerMgr* getSpeakerManager() const { return mSpeakers; } - void updateSpeakersList(const LLSD& speaker_updates); void processSessionUpdate(const LLSD& update); - void setSpeakers(const LLSD& speaker_list); - LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } EInstantMessage getDialogType() const { return mDialog; } void setDialogType(EInstantMessage dialog) { mDialog = dialog; } @@ -305,7 +302,6 @@ private: LLUUID mSessionUUID; std::string mSessionLabel; - LLVoiceChannel* mVoiceChannel; BOOL mSessionInitialized; LLSD mQueuedMsgsForInit; @@ -346,7 +342,6 @@ private: BOOL mProfileButtonEnabled; BOOL mCallBackEnabled; - LLIMSpeakerMgr* mSpeakers; LLPanelActiveSpeakers* mSpeakerPanel; // Optimization: Don't send "User is typing..." until the diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 3cf78f957b..556eb5ffd7 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -114,10 +114,84 @@ void toast_callback(const LLSD& msg){ LLIMModel::LLIMModel() { - addChangedCallback(toast_callback); addChangedCallback(LLIMFloater::newIMCallback); + addChangedCallback(toast_callback); +} + + +LLIMModel::LLIMSession::LLIMSession( const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id ) +: mSessionID(session_id), + mName(name), + mType(type), + mNumUnread(0), + mOtherParticipantID(other_participant_id), + mVoiceChannel(NULL), + mSpeakers(NULL) +{ + if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) + { + mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); + } + else + { + mVoiceChannel = new LLVoiceChannelGroup(session_id, name); + } + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + + // All participants will be added to the list of people we've recently interacted with. + mSpeakers->addListener(&LLRecentPeople::instance(), "add"); +} + +LLIMModel::LLIMSession::~LLIMSession() +{ + delete mSpeakers; + mSpeakers = NULL; + + // End the text IM session if necessary + if(gVoiceClient && mOtherParticipantID.notNull()) + { + switch(mType) + { + case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: + gVoiceClient->endUserIMSession(mOtherParticipantID); + break; + + default: + // Appease the linux compiler + break; + } + } + + // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). + mVoiceChannel->deactivate(); + + delete mVoiceChannel; + mVoiceChannel = NULL; } +LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const +{ + return get_if_there(LLIMModel::instance().sSessionsMap, session_id, + (LLIMModel::LLIMSession*) NULL); +} + +void LLIMModel::updateSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id) +{ + if (new_session_id == old_session_id) return; + + LLIMSession* session = findIMSession(old_session_id); + if (session) + { + session->mSessionID = new_session_id; + session->mVoiceChannel->updateSessionID(new_session_id); + + //*TODO set session initialized flag here? (IB) + + sSessionsMap.erase(old_session_id); + sSessionsMap[new_session_id] = session; + } +} void LLIMModel::testMessages() { @@ -153,7 +227,7 @@ bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage return false; } - LLIMSession* session = new LLIMSession(name, type, other_participant_id); + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id); sSessionsMap[session_id] = session; LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id); @@ -170,12 +244,12 @@ bool LLIMModel::clearSession(LLUUID session_id) return true; } +//*TODO remake it, instead of returing the list pass it as as parameter (IB) std::list LLIMModel::getMessages(LLUUID session_id, int start_index) { std::list return_list; - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); - + LLIMSession* session = findIMSession(session_id); if (!session) { llwarns << "session " << session_id << "does not exist " << llendl; @@ -202,13 +276,14 @@ std::list LLIMModel::getMessages(LLUUID session_id, int start_index) mChangedSignal(arg); // TODO: in the future is there a more efficient way to return these + //of course there is - return as parameter (IB) return return_list; } bool LLIMModel::addToHistory(LLUUID session_id, std::string from, std::string utf8_text) { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -231,7 +306,7 @@ bool LLIMModel::addToHistory(LLUUID session_id, std::string from, std::string ut bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -260,9 +335,9 @@ bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, } -const std::string& LLIMModel::getName(LLUUID session_id) +const std::string& LLIMModel::getName(const LLUUID& session_id) const { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -273,6 +348,66 @@ const std::string& LLIMModel::getName(LLUUID session_id) return session->mName; } +const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return -1; + } + + return session->mNumUnread; +} + +const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return LLUUID::null; + } + + return session->mOtherParticipantID; +} + +EInstantMessage LLIMModel::getType(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return IM_COUNT; + } + + return session->mType; +} + +LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mVoiceChannel; +} + +LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mSpeakers; +} + // TODO get rid of other participant ID void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) @@ -316,7 +451,7 @@ void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id) } - +//*TODO update list of messages in a LLIMSession (IB) void LLIMModel::sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, const LLUUID& other_participant_id, @@ -415,9 +550,16 @@ void LLIMModel::sendMessage(const std::string& utf8_text, LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id); if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID()); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } } // Add the recipient to the recent people list. + //*TODO should be deleted, because speaker manager updates through callback the recent list LLRecentPeople::instance().add(other_participant_id); } @@ -633,10 +775,8 @@ public: { if ( gIMMgr) { - LLFloaterIMPanel* floaterp = - gIMMgr->findFloaterBySession(mSessionID); - - if (floaterp) + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) { //we've accepted our invitation //and received a list of agents that were @@ -650,15 +790,20 @@ public: //but unfortunately, our base that we are receiving here //may not be the most up to date. It was accurate at //some point in time though. - floaterp->setSpeakers(content); + speaker_mgr->setSpeakers(content); //we now have our base of users in the session //that was accurate at some point, but maybe not now //so now we apply all of the udpates we've received //in case of race conditions - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(mSessionID)); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); + } + + LLFloaterIMPanel* floaterp = + gIMMgr->findFloaterBySession(mSessionID); + if (floaterp) + { if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE ) { floaterp->requestAutoConnect(); @@ -1104,6 +1249,12 @@ void LLIMMgr::addMessage( //no session ID...compute new one new_session_id = computeSessionID(dialog, other_participant_id); } + + if (!LLIMModel::getInstance()->findIMSession(new_session_id)) + { + LLIMModel::instance().newSession(session_id, session_name, dialog, other_participant_id); + } + floater = findFloaterBySession(new_session_id); if (!floater) { @@ -1169,6 +1320,14 @@ void LLIMMgr::addMessage( else { floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message + + //*TODO consider moving that speaker management stuff into model (IB) + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(new_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } } LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); @@ -1273,11 +1432,10 @@ LLUUID LLIMMgr::addP2PSession(const std::string& name, { LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id); - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if(floater) + LLVoiceChannelP2P* voice_channel = (LLVoiceChannelP2P*) LLIMModel::getInstance()->getSpeakerManager(session_id); + if (voice_channel) { - LLVoiceChannelP2P* voice_channelp = (LLVoiceChannelP2P*)floater->getVoiceChannel(); - voice_channelp->setSessionHandle(voice_session_handle, caller_uri); + voice_channel->setSessionHandle(voice_session_handle, caller_uri); } return session_id; @@ -1312,6 +1470,11 @@ LLUUID LLIMMgr::addSession( LLUUID session_id = computeSessionID(dialog,other_participant_id); + if (!LLIMModel::getInstance()->findIMSession(session_id)) + { + LLIMModel::instance().newSession(session_id, name, dialog, other_participant_id); + } + LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(!floater) { @@ -1335,17 +1498,10 @@ LLUUID LLIMMgr::addSession( noteMutedUsers(floater, ids); } } - else - { - // *TODO: Remove this? Otherwise old communicate window opens on - // second initiation of IM session from People panel? - // floater->openFloater(); - } - //mTabContainer->selectTabPanel(panel); floater->setInputFocus(TRUE); LLIMFloater::show(session_id); - notifyObserverSessionAdded(floater->getSessionID(), name, other_participant_id); - return floater->getSessionID(); + + return session_id; } // This removes the panel referenced by the uuid, and then restores @@ -1705,7 +1861,6 @@ LLFloaterIMPanel* LLIMMgr::createFloater( LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; LLFloaterChatterBox::getInstance()->addFloater(floater, FALSE, i_pt); mFloaters.insert(floater->getHandle()); - LLIMModel::instance().newSession(session_id, session_label, dialog, other_participant_id); return floater; } @@ -1825,24 +1980,25 @@ public: gIMMgr->updateFloaterSessionID( temp_session_id, session_id); + + LLIMModel::getInstance()->updateSessionID(temp_session_id, session_id); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->setSpeakers(body); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); + } + LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); if (floaterp) { - floaterp->setSpeakers(body); - - //apply updates we've possibly received previously - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(session_id)); - if ( body.has("session_info") ) { floaterp->processSessionUpdate(body["session_info"]); } - - //aply updates we've possibly received previously - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(session_id)); } + gIMMgr->clearPendingAgentListUpdates(session_id); } else @@ -1932,15 +2088,15 @@ public: const LLSD& context, const LLSD& input) const { - LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID()); - if (floaterp) + const LLUUID& session_id = input["body"]["session_id"].asUUID(); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) { - floaterp->updateSpeakersList( - input["body"]); + speaker_mgr->updateSpeakers(input["body"]); } else { - //we don't have a floater yet..something went wrong + //we don't have a speaker manager yet..something went wrong //we are probably receiving an update here before //a start or an acceptance of an invitation. Race condition. gIMMgr->addPendingAgentListUpdates( diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 219af0705d..9a94d01bb2 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,6 +34,8 @@ #define LL_LLIMVIEW_H #include "lldarray.h" +#include "llfloateractivespeakers.h" //for LLIMSpeakerMgr +#include "llimpanel.h" //for voice channels #include "llmodaldialog.h" #include "llinstantmessage.h" #include "lluuid.h" @@ -50,21 +52,40 @@ public: struct LLIMSession { - LLIMSession(std::string name, EInstantMessage type, LLUUID other_participant_id) - :mName(name), mType(type), mNumUnread(0), mOtherParticipantID(other_participant_id) {} - + LLIMSession(const LLUUID& session_id, const std::string& name, + const EInstantMessage& type, const LLUUID& other_participant_id); + virtual ~LLIMSession(); + + LLUUID mSessionID; std::string mName; EInstantMessage mType; LLUUID mOtherParticipantID; S32 mNumUnread; std::list mMsgs; + + LLVoiceChannel* mVoiceChannel; + LLIMSpeakerMgr* mSpeakers; }; LLIMModel(); + //*TODO make it non-static as LLIMMOdel is a singleton (IB) static std::map sSessionsMap; //mapping session_id to session + boost::signals2::signal mChangedSignal; + + /** + * Find an IM Session corresponding to session_id + * Returns NULL if the session does not exist + */ + LLIMSession* findIMSession(const LLUUID& session_id) const; + + /** + * Rebind session data to a new session id. + */ + void updateSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id); + boost::signals2::connection addChangedCallback( boost::function cb ); bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id); @@ -72,10 +93,42 @@ public: std::list getMessages(LLUUID session_id, int start_index = 0); bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text); bool addToHistory(LLUUID session_id, std::string from, std::string utf8_text); - //used to get the name of the session, for use as the title - //currently just the other avatar name - const std::string& getName(LLUUID session_id); - + //used to get the name of the session, for use as the title + //currently just the other avatar name + const std::string& getName(const LLUUID& session_id) const; + + /** + * Get number of unread messages in a session with session_id + * Returns -1 if the session with session_id doesn't exist + */ + const S32 getNumUnread(const LLUUID& session_id) const; + + /** + * Get uuid of other participant in a session with session_id + * Returns LLUUID::null if the session doesn't exist + * + * *TODO what to do with other participants in ad-hoc and group chats? + */ + const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; + + /** + * Get type of a session specified by session_id + * Returns EInstantMessage::IM_COUNT if the session does not exist + */ + EInstantMessage getType(const LLUUID& session_id) const; + + /** + * Get voice channel for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; + + /** + * Get im speaker manager for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; + static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id); static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, const std::vector& ids, EInstantMessage dialog); diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index b53bb586f3..8430937933 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -65,6 +65,7 @@ LLNearbyChat::LLNearbyChat(const LLSD& key) : mChatCaptionPanel(NULL), mChatHistoryEditor(NULL) { + m_isDirty = false; } LLNearbyChat::~LLNearbyChat() @@ -181,7 +182,7 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat) return text_color; } -void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& color) +void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color) { std::string line = chat.mText; @@ -194,25 +195,28 @@ void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, cons bool prepend_newline = true; if (gSavedSettings.getBOOL("ChatShowTimestamps")) { - edit->appendTime(prepend_newline); + mChatHistoryEditor->appendTime(prepend_newline); prepend_newline = false; } // If the msg is from an agent (not yourself though), // extract out the sender name and replace it with the hotlinked name. + + std::string str_URL = chat.mURL; + if (chat.mSourceType == CHAT_SOURCE_AGENT && chat.mFromID != LLUUID::null) { - chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); + str_URL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); } // If the chat line has an associated url, link it up to the name. - if (!chat.mURL.empty() + if (!str_URL.empty() && (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0)) { std::string start_line = line.substr(0, chat.mFromName.length() + 1); line = line.substr(chat.mFromName.length() + 1); - edit->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL)); + mChatHistoryEditor->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,str_URL)); prepend_newline = false; } @@ -225,11 +229,9 @@ void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, cons else if (2 == font_size) font_name = "sansserifbig"; - edit->appendColoredText(line, false, prepend_newline, color, font_name); + mChatHistoryEditor->appendColoredText(line, false, prepend_newline, color, font_name); } - - void LLNearbyChat::addMessage(const LLChat& chat) { LLColor4 color = nearbychat_get_text_color(chat); @@ -254,7 +256,7 @@ void LLNearbyChat::addMessage(const LLChat& chat) mChatHistoryEditor->setParseHighlights(TRUE); if (!chat.mMuted) - nearbychat_add_timestamped_line(mChatHistoryEditor, chat, color); + add_timestamped_line(chat, color); } void LLNearbyChat::onNearbySpeakers() @@ -482,9 +484,16 @@ BOOL LLNearbyChat::handleRightMouseDown(S32 x, S32 y, MASK mask) void LLNearbyChat::onOpen(const LLSD& key ) { - LLNotificationsUI::LLScreenChannel* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); if(chat_channel) { chat_channel->removeToastsFromChannel(); } } + +void LLNearbyChat::draw () +{ + LLFloater::draw(); +} + + diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index efa2e479e6..599e6b6859 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -76,7 +76,10 @@ public: virtual void onOpen (const LLSD& key); + virtual void draw (); + private: + void add_timestamped_line(const LLChat& chat, const LLColor4& color); void pinn_panel(); void float_panel(); @@ -86,10 +89,11 @@ private: S32 mStart_X; S32 mStart_Y; - //LLResizeBar* mResizeBar[RESIZE_BAR_COUNT]; LLHandle mPopupMenuHandle; LLPanel* mChatCaptionPanel; LLViewerTextEditor* mChatHistoryEditor; + + bool m_isDirty; }; #endif diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 7eb5d91e53..eb42e83994 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -41,30 +41,227 @@ #include "llviewercontrol.h" #include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance +#include "llviewerwindow.h"//for screen channel position //add LLNearbyChatHandler to LLNotificationsUI namespace -namespace LLNotificationsUI{ +using namespace LLNotificationsUI; +//----------------------------------------------------------------------------------------------- +//LLNearbyChatScreenChannel +//----------------------------------------------------------------------------------------------- +LLToastPanelBase* createToastPanel() +{ + LLNearbyChatToastPanel* item = LLNearbyChatToastPanel::createInstance(); + static S32 chat_item_width = 304; + item->setWidth(chat_item_width); + return item; +} + + +class LLNearbyChatScreenChannel: public LLScreenChannelBase +{ +public: + LLNearbyChatScreenChannel(const LLUUID& id):LLScreenChannelBase(id) { mActiveMessages = 0;}; + void init (S32 channel_left, S32 channel_right); + + void addNotification (LLSD& notification); + void arrangeToasts (); + void showToastsBottom (); + + typedef boost::function create_toast_panel_callback_t; + void setCreatePanelCallback(create_toast_panel_callback_t value) { m_create_toast_panel_callback_t = value;} + + void onToastDestroyed (LLToast* toast); + void onToastFade (LLToast* toast); + + // hide all toasts from screen, but not remove them from a channel + virtual void hideToastsFromScreen() + { + }; + // removes all toasts from a channel + virtual void removeToastsFromChannel() + { + for(std::vector::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it) + { + LLToast* toast = (*it); + toast->setVisible(FALSE); + toast->stopTimer(); + m_toast_pool.push_back(toast); + + } + m_active_toasts.clear(); + }; + +protected: + void createOverflowToast(S32 bottom, F32 timer); + + create_toast_panel_callback_t m_create_toast_panel_callback_t; + + bool createPoolToast(); + + std::vector m_active_toasts; + std::list m_toast_pool; + + S32 mActiveMessages; +}; + +void LLNearbyChatScreenChannel::init(S32 channel_left, S32 channel_right) +{ + S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); + S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom; + setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); + setVisible(TRUE); +} + + +void LLNearbyChatScreenChannel::createOverflowToast(S32 bottom, F32 timer) +{ + //we don't need overflow toast in nearby chat +} + +void LLNearbyChatScreenChannel::onToastDestroyed(LLToast* toast) +{ +} + +void LLNearbyChatScreenChannel::onToastFade(LLToast* toast) +{ + //fade mean we put toast to toast pool + if(!toast) + return; + m_toast_pool.push_back(toast); + + std::vector::iterator pos = std::find(m_active_toasts.begin(),m_active_toasts.end(),toast); + if(pos!=m_active_toasts.end()) + m_active_toasts.erase(pos); + + arrangeToasts(); +} + + +bool LLNearbyChatScreenChannel::createPoolToast() +{ + LLToastPanelBase* panel= m_create_toast_panel_callback_t(); + if(!panel) + return false; + + LLToast::Params p; + p.panel = panel; + + LLToast* toast = new LLToast(p); + + + toast->setOnFadeCallback(boost::bind(&LLNearbyChatScreenChannel::onToastFade, this, _1)); + toast->setOnToastDestroyedCallback(boost::bind(&LLNearbyChatScreenChannel::onToastDestroyed, this, _1)); + + m_toast_pool.push_back(toast); + return true; +} + +void LLNearbyChatScreenChannel::addNotification(LLSD& notification) +{ + //look in pool. if there is any message + + + if(m_toast_pool.empty()) + { + //"pool" is empty - create one more panel + if(!createPoolToast())//created toast will go to pool. so next call will find it + return; + addNotification(notification); + return; + } + + //take 1st element from pool, (re)initialize it, put it in active toasts + + LLToast* toast = m_toast_pool.back(); + + m_toast_pool.pop_back(); + + + LLToastPanelBase* panel = dynamic_cast(toast->getPanel()); + if(!panel) + return; + panel->init(notification); + + toast->reshapeToPanel(); + toast->resetTimer(); + + m_active_toasts.insert(m_active_toasts.begin(),toast); + + arrangeToasts(); +} + +void LLNearbyChatScreenChannel::arrangeToasts() +{ + if(m_active_toasts.size() == 0 || mIsHovering) + return; + + hideToastsFromScreen(); + + showToastsBottom(); +} + +void LLNearbyChatScreenChannel::showToastsBottom() +{ + LLRect rect = getRect(); + + LLRect toast_rect; + S32 bottom = getRect().mBottom; + + for(std::vector::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it) + { + LLToast* toast = (*it); + toast_rect = toast->getRect(); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight()); + + toast->setRect(toast_rect); + + if(toast->getRect().mTop > getRect().getHeight()) + { + while(it!=m_active_toasts.end()) + { + (*it)->setVisible(FALSE); + (*it)->stopTimer(); + m_toast_pool.push_back(*it); + it=m_active_toasts.erase(it); + } + break; + } + toast->setVisible(TRUE); + bottom = toast->getRect().mTop; + } +} + + +//----------------------------------------------------------------------------------------------- +//LLNearbyChatHandler +//----------------------------------------------------------------------------------------------- LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id) { mType = type; - LLChannelManager::Params p; - p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID")); // Getting a Channel for our notifications - mChannel = LLChannelManager::getInstance()->getChannel(p); + LLNearbyChatScreenChannel* channel = new LLNearbyChatScreenChannel(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + + LLNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel; + + channel->setCreatePanelCallback(callback); + + mChannel = LLChannelManager::getInstance()->addChannel(channel); mChannel->setOverflowFormatString("You have %d unread nearby chat messages"); } + LLNearbyChatHandler::~LLNearbyChatHandler() { } + void LLNearbyChatHandler::initChannel() { LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat", LLSD()); S32 channel_right_bound = nearby_chat->getRect().mRight; - S32 channel_width = nearby_chat->getRect().mRight - 16; //HACK: 16 - ? + S32 channel_width = nearby_chat->getRect().mRight; mChannel->init(channel_right_bound - channel_width, channel_right_bound); } @@ -77,41 +274,42 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg) if(chat_msg.mText.empty()) return;//don't process empty messages - + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat", LLSD()); nearby_chat->addMessage(chat_msg); if(nearby_chat->getVisible()) return;//no need in toast if chat is visible - + // arrange a channel on a screen if(!mChannel->getVisible()) { initChannel(); } - + LLUUID id; id.generate(); - LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); - - item->setMessage(chat_msg); - //static S32 chat_item_width = nearby_chat->getRect().getWidth() - 16; - static S32 chat_item_width = 304; - item->setWidth(chat_item_width); - item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + LLNearbyChatScreenChannel* channel = dynamic_cast(mChannel); - item->setVisible(true); - LLToast::Params p; - p.notif_id = id; - p.panel = item; - p.on_delete_toast = boost::bind(&LLNearbyChatHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + if(channel) + { + LLSD notification; + notification["id"] = id; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + + channel->addNotification(notification); + } + } void LLNearbyChatHandler::onDeleteToast(LLToast* toast) { } -} + diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index 3893eaa0d4..755f1235a6 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -100,16 +100,23 @@ bool LLAlertHandler::processNotification(const LLSD& notify) p.can_fade = false; p.is_modal = mIsModal; p.on_delete_toast = boost::bind(&LLAlertHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->addToast(p); } else if (notify["sigtype"].asString() == "change") { LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); - mChannel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); } else { - mChannel->killToastByNotificationID(notification->getID()); + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->killToastByNotificationID(notification->getID()); } return true; } diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp index c488d37ea5..ffa92b543c 100644 --- a/indra/newview/llnotificationgrouphandler.cpp +++ b/indra/newview/llnotificationgrouphandler.cpp @@ -89,7 +89,10 @@ bool LLGroupHandler::processNotification(const LLSD& notify) p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLGroupHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager mNewNotificationSignal(); diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 90ff5fbaac..cd4e640ec4 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -104,8 +104,8 @@ protected: // at the moment, when a handlers creates a channel. virtual void initChannel()=0; - LLScreenChannel* mChannel; - e_notification_type mType; + LLScreenChannelBase* mChannel; + e_notification_type mType; }; diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 72855ac0fd..070af432d6 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -48,7 +48,11 @@ LLScriptHandler::LLScriptHandler(e_notification_type type, const LLSD& id) // Getting a Channel for our notifications mChannel = LLChannelManager::getInstance()->createNotificationChannel(); mChannel->setControlHovering(true); - mChannel->setOnRejectToastCallback(boost::bind(&LLScriptHandler::onRejectToast, this, _1)); + + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->setOnRejectToastCallback(boost::bind(&LLScriptHandler::onRejectToast, this, _1)); + } //-------------------------------------------------------------------------- @@ -92,7 +96,10 @@ bool LLScriptHandler::processNotification(const LLSD& notify) p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager mNewNotificationSignal(); diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 740acb6365..5186a93569 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -93,8 +93,9 @@ bool LLTipHandler::processNotification(const LLSD& notify) p.is_tip = true; p.can_be_stored = false; - mChannel->addToast(p); - + LLScreenChannel* channel = dynamic_cast(mChannel); + if(channel) + channel->addToast(p); } else if (notify["sigtype"].asString() == "delete") { diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 649697e091..7ccff73080 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -313,7 +313,7 @@ void LLPanelProfileTab::scrollToTop() { LLScrollContainer* scrollContainer = findChild("profile_scroll"); if (scrollContainer) - scrollContainer->goToTop(); + scrollContainer->goToTop(); } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 490c845c94..2b584910a3 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -195,7 +195,7 @@ BOOL LLPanelGroup::postBuild() if(panel_land) mTabs.push_back(panel_land); if(panel_general) - panel_general->setupCtrls(this); + panel_general->setupCtrls(this); return TRUE; } @@ -206,8 +206,8 @@ void LLPanelGroup::reposButton(const std::string& name) if(!button) return; LLRect btn_rect = button->getRect(); - btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); - button->setRect(btn_rect); + btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); + button->setRect(btn_rect); } void LLPanelGroup::reshape(S32 width, S32 height, BOOL called_from_parent ) @@ -235,7 +235,14 @@ void LLPanelGroup::onBtnCreate() if(!panel_general) return; std::string apply_mesg; - panel_general->apply(apply_mesg);//yes yes you need to call apply to create... + if(panel_general->apply(apply_mesg))//yes yes you need to call apply to create... + return; + if ( !apply_mesg.empty() ) + { + LLSD args; + args["MESSAGE"] = apply_mesg; + LLNotifications::instance().add("GenericAlert", args); + } } void LLPanelGroup::onBtnRefresh(void* user_data) diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 5eb7b8f5f5..2e1d971995 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -835,6 +835,7 @@ void LLPanelGroupGeneral::reset() { std::string empty_str = ""; mEditCharter->setText(empty_str); + mGroupNameEditor->setText(empty_str); } { @@ -850,6 +851,7 @@ void LLPanelGroupGeneral::reset() { mComboMature->setEnabled(true); mComboMature->setVisible( !gAgent.isTeen() ); + mComboMature->selectFirstItem(); } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 6a41b6feb9..b2a0a01005 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -60,11 +60,8 @@ #include "llvoiceclient.h" #include "llworld.h" -using namespace LLOldEvents; - #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 -#define RECENT_LIST_UPDATE_DELAY 1 static const std::string NEARBY_TAB_NAME = "nearby_panel"; static const std::string FRIENDS_TAB_NAME = "friends_panel"; @@ -102,7 +99,7 @@ static LLRegisterPanelClassWrapper t_people("panel_people"); class LLPanelPeople::Updater { public: - typedef boost::function callback_t; + typedef boost::function callback_t; Updater(callback_t cb) : mCallback(cb) { @@ -112,16 +109,6 @@ public: { } - /** - * Force the list updates. - * - * This may start repeated updates until all names are complete. - */ - virtual void forceUpdate() - { - updateList(); - } - /** * Activate/deactivate updater. * @@ -130,9 +117,9 @@ public: virtual void setActive(bool) {} protected: - bool updateList(U32 mask = 0) + void updateList() { - return mCallback(mask); + mCallback(); } callback_t mCallback; @@ -147,6 +134,11 @@ public: { mEventTimer.stop(); } + + virtual BOOL tick() // from LLEventTimer + { + return FALSE; + } }; /** @@ -178,13 +170,6 @@ public: LLAvatarTracker::instance().removeObserver(this); } - /*virtual*/ void forceUpdate() - { - // Perform updates until all names are loaded. - if (!updateList(LLFriendObserver::ADD)) - changed(LLFriendObserver::ADD); - } - /*virtual*/ void changed(U32 mask) { // events can arrive quickly in bulk - we need not process EVERY one of them - @@ -198,12 +183,12 @@ public: /*virtual*/ BOOL tick() { - if (updateList(mMask)) - { - // Got all names, stop updates. - mEventTimer.stop(); - mMask = 0; - } + if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + updateList(); + + // Stop updates. + mEventTimer.stop(); + mMask = 0; return FALSE; } @@ -329,68 +314,9 @@ class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2:: public: LLRecentListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, RECENT_LIST_UPDATE_DELAY) - { - LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::onRecentPeopleChanged, this)); - } - -private: - /*virtual*/ void forceUpdate() - { - onRecentPeopleChanged(); - } - - /*virtual*/ BOOL tick() - { - // Update the list until we get all the names. - if (updateList()) - { - // Got all names, stop updates. - mEventTimer.stop(); - } - - return FALSE; - } - - void onRecentPeopleChanged() - { - if (!updateList()) - { - // Some names are incomplete, schedule another update. - mEventTimer.start(); - } - } -}; - -/** - * Updates the group list on events from LLAgent. - */ -class LLGroupListUpdater : public LLPanelPeople::Updater, public LLSimpleListener -{ - LOG_CLASS(LLGroupListUpdater); - -public: - LLGroupListUpdater(callback_t cb) - : LLPanelPeople::Updater(cb) - { - gAgent.addListener(this, "new group"); - } - - ~LLGroupListUpdater() + : LLAvatarListUpdater(cb, 0) { - gAgent.removeListener(this); - } - - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) - { - // Why is "new group" sufficient? - if (event->desc() == "new group") - { - updateList(); - return true; - } - - return false; + LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::updateList, this)); } }; @@ -404,12 +330,12 @@ LLPanelPeople::LLPanelPeople() mOnlineFriendList(NULL), mAllFriendList(NULL), mNearbyList(NULL), - mRecentList(NULL) + mRecentList(NULL), + mGroupList(NULL) { - mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::onFriendListUpdate,this, _1)); + mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); - mGroupListUpdater = new LLGroupListUpdater (boost::bind(&LLPanelPeople::updateGroupList, this)); } LLPanelPeople::~LLPanelPeople() @@ -417,7 +343,6 @@ LLPanelPeople::~LLPanelPeople() delete mNearbyListUpdater; delete mFriendListUpdater; delete mRecentListUpdater; - delete mGroupListUpdater; LLView::deleteViewByHandle(mGroupPlusMenuHandle); LLView::deleteViewByHandle(mNearbyViewSortMenuHandle); @@ -512,7 +437,7 @@ BOOL LLPanelPeople::postBuild() buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this)); getChild(NEARBY_TAB_NAME)->childSetAction("nearby_view_sort_btn",boost::bind(&LLPanelPeople::onNearbyViewSortButtonClicked, this)); - getChild(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this)); + getChild(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this)); getChild(FRIENDS_TAB_NAME)->childSetAction("friends_viewsort_btn",boost::bind(&LLPanelPeople::onFriendsViewSortButtonClicked, this)); getChild(GROUP_TAB_NAME)->childSetAction("groups_viewsort_btn",boost::bind(&LLPanelPeople::onGroupsViewSortButtonClicked, this)); @@ -547,137 +472,71 @@ BOOL LLPanelPeople::postBuild() if(recent_view_sort) mRecentViewSortMenuHandle = recent_view_sort->getHandle(); - - - // Perform initial update. - mFriendListUpdater->forceUpdate(); - mNearbyListUpdater->forceUpdate(); - mGroupListUpdater->forceUpdate(); - mRecentListUpdater->forceUpdate(); - // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); return TRUE; } -void LLPanelPeople::applyFilterToTab(const std::string& tab_name) -{ - if (tab_name == FRIENDS_TAB_NAME) // this tab has two lists - filterFriendList(); - else if (tab_name == NEARBY_TAB_NAME) - filterNearbyList(); - else if (tab_name == RECENT_TAB_NAME) - filterRecentList(); - else if (tab_name == GROUP_TAB_NAME) - updateGroupList(); -} - -bool LLPanelPeople::updateFriendList(U32 changed_mask) +void LLPanelPeople::updateFriendList() { - // Refresh names. - if (changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) - { - // get all buddies we know about - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - LLAvatarTracker::buddy_map_t all_buddies; - av_tracker.copyBuddyList(all_buddies); - - // *TODO: it's suboptimal to rebuild the whole lists on online status change. + if (!mOnlineFriendList || !mAllFriendList) + return; - // save them to the online and all friends vectors - mOnlineFriendVec.clear(); - mAllFriendVec.clear(); + // get all buddies we know about + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); - LLFriendCardsManager::folderid_buddies_map_t listMap; + // save them to the online and all friends vectors + LLAvatarList::uuid_vector_t& online_friendsp = mOnlineFriendList->getIDs(); + LLAvatarList::uuid_vector_t& all_friendsp = mAllFriendList->getIDs(); - // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. - LLFriendCardsManager::instance().collectFriendsLists(listMap); - if (listMap.size() > 0) - { - lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl; - mAllFriendVec = listMap.begin()->second; - } - else - { - lldebugs << "Friends Cards were not found" << llendl; - } + all_friendsp.clear(); + online_friendsp.clear(); - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - for (; buddy_it != all_buddies.end(); ++buddy_it) - { - LLUUID buddy_id = buddy_it->first; - if (av_tracker.isBuddyOnline(buddy_id)) - mOnlineFriendVec.push_back(buddy_id); - } + LLFriendCardsManager::folderid_buddies_map_t listMap; - return filterFriendList(); + // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. + LLFriendCardsManager::instance().collectFriendsLists(listMap); + if (listMap.size() > 0) + { + lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl; + all_friendsp = listMap.begin()->second; + } + else + { + lldebugs << "Friends Cards were not found" << llendl; } - return true; -} - -bool LLPanelPeople::updateNearbyList() -{ - LLWorld::getInstance()->getAvatars(&mNearbyVec, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); - filterNearbyList(); - - return true; -} - -bool LLPanelPeople::updateRecentList() -{ - LLRecentPeople::instance().get(mRecentVec); - filterRecentList(); - - return true; -} - -bool LLPanelPeople::updateGroupList() -{ - if (!mGroupList) - return true; // there's no point in further updates + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + if (av_tracker.isBuddyOnline(buddy_id)) + online_friendsp.push_back(buddy_id); + } - bool have_names = mGroupList->update(mFilterSubString); - updateButtons(); - return have_names; + mOnlineFriendList->setDirty(); + mAllFriendList->setDirty(); } -bool LLPanelPeople::filterFriendList() +void LLPanelPeople::updateNearbyList() { - if (!mOnlineFriendList || !mAllFriendList) - return true; // there's no point in further updates - - // We must always update Friends list to clear the latest removed friend. - bool have_names = - mOnlineFriendList->update(mOnlineFriendVec, mFilterSubString) & - mAllFriendList->update(mAllFriendVec, mFilterSubString); - - - updateButtons(); - return have_names; -} + if (!mNearbyList) + return; -bool LLPanelPeople::filterNearbyList() -{ - bool have_names = mNearbyList->update(mNearbyVec, mFilterSubString); - updateButtons(); - return have_names; + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + mNearbyList->setDirty(); } -bool LLPanelPeople::filterRecentList() +void LLPanelPeople::updateRecentList() { if (!mRecentList) - return true; - - if (mRecentVec.size() > 0) - { - bool updated = mRecentList->update(mRecentVec, mFilterSubString); - updateButtons(); - return updated; - } + return; - return true; + LLRecentPeople::instance().get(mRecentList->getIDs()); + mRecentList->setDirty(); } void LLPanelPeople::buttonSetVisible(std::string btn_name, BOOL visible) @@ -846,16 +705,19 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) LLStringUtil::toUpper(mFilterSubString); LLStringUtil::trimHead(mFilterSubString); - // Apply new filter to current tab. - applyFilterToTab(getActiveTabName()); + // Apply new filter. + mNearbyList->setNameFilter(mFilterSubString); + mOnlineFriendList->setNameFilter(mFilterSubString); + mAllFriendList->setNameFilter(mFilterSubString); + mRecentList->setNameFilter(mFilterSubString); + mGroupList->setNameFilter(mFilterSubString); } void LLPanelPeople::onTabSelected(const LLSD& param) { std::string tab_name = getChild(param.asString())->getName(); mNearbyListUpdater->setActive(tab_name == NEARBY_TAB_NAME); - applyFilterToTab(tab_name); - // No need to call updateButtons() because applyFilterToTab() does that. + updateButtons(); if (GROUP_TAB_NAME == tab_name) mFilterEditor->setLabel(getString("groups_filter_label")); @@ -960,17 +822,6 @@ void LLPanelPeople::onAvatarPicked( LLAvatarActions::requestFriendshipDialog(ids[0], names[0]); } -bool LLPanelPeople::onFriendListUpdate(U32 changed_mask) -{ - bool have_names = updateFriendList(changed_mask); - - // Update online status in the Recent tab. - // *TODO: isn't it too much to update the whole list? -// updateRecentList(); // mantipov: seems online status should be supported by LLAvatarListItem itself. - - return have_names; -} - void LLPanelPeople::onGroupPlusButtonClicked() { LLMenuGL* plus_menu = (LLMenuGL*)mGroupPlusMenuHandle.get(); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 8cd3cc7feb..de27814388 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -58,15 +58,10 @@ public: private: // methods indirectly called by the updaters - bool updateFriendList(U32 changed_mask); - bool updateNearbyList(); - bool updateRecentList(); - bool updateGroupList(); - - bool filterFriendList(); - bool filterNearbyList(); - bool filterRecentList(); - void applyFilterToTab(const std::string& tab_name); + void updateFriendList(); + void updateNearbyList(); + void updateRecentList(); + void updateButtons(); const std::string& getActiveTabName() const; LLUUID getCurrentItemID() const; @@ -110,7 +105,6 @@ private: void onRecentViewSortMenuItemClicked(const LLSD& userdata); // misc callbacks - bool onFriendListUpdate(U32 changed_mask); static void onAvatarPicked( const std::vector& names, const std::vector& ids, @@ -135,21 +129,8 @@ private: Updater* mFriendListUpdater; Updater* mNearbyListUpdater; Updater* mRecentListUpdater; - Updater* mGroupListUpdater; std::string mFilterSubString; - - // The vectors below contain up-to date avatar lists - // for the corresponding tabs. - // When the user enters a filter, it gets applied - // to all the vectors and the result is shown in the tabs. - // We don't need to have such a vector for the groups tab - // since re-fetching the groups list is always fast. - typedef std::vector uuid_vector_t; - uuid_vector_t mNearbyVec; - uuid_vector_t mOnlineFriendVec; - uuid_vector_t mAllFriendVec; - uuid_vector_t mRecentVec; }; #endif //LL_LLPANELPEOPLE_H diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 42185d28e5..5df3d4f1d6 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -39,8 +39,10 @@ #include "message.h" #include "llagent.h" #include "llbutton.h" +#include "lllineeditor.h" #include "llparcel.h" #include "llviewerparcelmgr.h" +#include "lltexteditor.h" #include "lltexturectrl.h" #include "lluiconstants.h" #include "llworldmap.h" @@ -73,7 +75,8 @@ LLPanelPick::LLPanelPick(BOOL edit_mode/* = FALSE */) mPickId(LLUUID::null), mCreatorId(LLUUID::null), mDataReceived(FALSE), - mIsPickNew(false) + mIsPickNew(false), + mLocationChanged(false) { if (edit_mode) { @@ -123,6 +126,16 @@ BOOL LLPanelPick::postBuild() if (mEditMode) { + enableSaveButton(FALSE); + + mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); + + LLLineEditor* line_edit = getChild("pick_name"); + line_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1), NULL); + + LLTextEditor* text_edit = getChild("pick_desc"); + text_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); + childSetAction("cancel_btn", boost::bind(&LLPanelPick::onClickCancel, this)); childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPick::onClickSet, this)); childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPick::onClickSave, this)); @@ -287,6 +300,26 @@ void LLPanelPick::setEditMode( BOOL edit_mode ) updateButtons(); } +void LLPanelPick::onPickChanged(LLUICtrl* ctrl) +{ + if(mLocationChanged) + { + // Pick was enabled in onClickSet + return; + } + + if( mSnapshotCtrl->isDirty() + || getChild("pick_name")->isDirty() + || getChild("pick_desc")->isDirty() ) + { + enableSaveButton(TRUE); + } + else + { + enableSaveButton(FALSE); + } +} + ////////////////////////////////////////////////////////////////////////// // PROTECTED AREA ////////////////////////////////////////////////////////////////////////// @@ -466,6 +499,9 @@ void LLPanelPick::onClickSet() mSimName = parcel->getName(); } setPickLocation(createLocationText(std::string(""), SET_LOCATION_NOTICE, mSimName, mPosGlobal)); + + mLocationChanged = true; + enableSaveButton(TRUE); } // static @@ -552,3 +588,12 @@ void LLPanelPick::processParcelInfo(const LLParcelData& parcel_data) //*NOTE we don't removeObserver(...) ourselves cause LLRemoveParcelProcessor does it for us } + +void LLPanelPick::enableSaveButton(bool enable) +{ + if(!mEditMode) + { + return; + } + childSetEnabled(XML_BTN_SAVE, enable); +} diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 7ce58b59af..82cba72bc4 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -74,6 +74,8 @@ public: // switches the panel to either View or Edit mode void setEditMode(BOOL edit_mode); + void onPickChanged(LLUICtrl* ctrl); + // because this panel works in two modes (edit/view) we are // free from managing two panel for editing and viewing picks and so // are free from controlling switching between them in the parent panel (e.g. Me Profile) @@ -128,6 +130,8 @@ protected: void onClickSave(); void onClickCancel(); + void enableSaveButton(bool enable); + protected: BOOL mEditMode; LLTextureCtrl* mSnapshotCtrl; @@ -146,6 +150,7 @@ protected: std::string mLocation; commit_callback_t mBackCb; + bool mLocationChanged; }; #endif // LL_LLPANELPICK_H diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index 93317e613f..e74afba25a 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -126,8 +126,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) mPicksList->addItem(picture, pick_value); picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickItem, this, _1)); - picture->setRightMouseDownCallback(boost::bind(&LLPanelPicks::onRightMouseDownItem, this, _1, _2, _3, _4)); - picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); + picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); } @@ -260,8 +259,10 @@ void LLPanelPicks::onClickMap() } -void LLPanelPicks::onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask) +void LLPanelPicks::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask) { + updateButtons(); + if (mPopupMenu) { mPopupMenu->buildDrawLabels(); diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 27a21305b3..7ebdc3089c 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -100,7 +100,7 @@ private: void updateButtons(); virtual void onDoubleClickItem(LLUICtrl* item); - virtual void onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask); + virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask); LLPanelProfile* getProfilePanel(); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 4e070df7eb..80ecc95afb 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -337,7 +337,7 @@ void LLPanelPlaces::onFilterEdit(const std::string& search_string) LLStringUtil::trimHead(mFilterSubString); if (mActivePanel) - mActivePanel->onSearchEdit(mFilterSubString); + mActivePanel->onSearchEdit(mFilterSubString); } } @@ -386,7 +386,7 @@ void LLPanelPlaces::onTeleportButtonClicked() else { if (mActivePanel) - mActivePanel->onTeleport(); + mActivePanel->onTeleport(); } } @@ -432,7 +432,7 @@ void LLPanelPlaces::onShowOnMapButtonClicked() else { if (mActivePanel) - mActivePanel->onShowOnMap(); + mActivePanel->onShowOnMap(); } } @@ -510,7 +510,7 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) addChild(mPickPanel); mPickPanel->setExitCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); - } + } togglePickPanel(TRUE); @@ -733,7 +733,7 @@ void LLPanelPlaces::updateVerbs() else { if (mActivePanel) - mActivePanel->updateVerbs(); + mActivePanel->updateVerbs(); } } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index f6672d9c8b..32cccc4ac0 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -306,12 +306,12 @@ void LLTeleportHistoryPanel::showTeleportHistory() if (curr_tab <= tabs_cnt - 4) { - curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() - seconds_in_day); + curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() - seconds_in_day); } else if (curr_tab == tabs_cnt - 3) // 6 day and older, low boundary is 1 month { curr_date = LLDate::now(); - curr_date.split(&curr_year, &curr_month, &curr_day); + curr_date.split(&curr_year, &curr_month, &curr_day); curr_month--; if (0 == curr_month) { @@ -376,7 +376,7 @@ void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected) S32 tabs_cnt = mItemContainers.size(); for (S32 n = 0; n < tabs_cnt; n++) - { + { LLAccordionCtrlTab* tab = mItemContainers.get(n); if (!tab->getVisible()) @@ -390,7 +390,7 @@ void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected) continue; flv->resetSelection(true); - } + } updateVerbs(); } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 082bba027f..06bdf64b19 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -55,36 +55,30 @@ using namespace LLNotificationsUI; bool LLScreenChannel::mWasStartUpToastShown = false; //-------------------------------------------------------------------------- -LLScreenChannel::LLScreenChannel(LLUUID& id): mOverflowToastPanel(NULL), mStartUpToastPanel(NULL), - mToastAlignment(NA_BOTTOM), mCanStoreToasts(true), - mHiddenToastsNum(0), mOverflowToastHidden(false), - mIsHovering(false), mControlHovering(false), - mShowToasts(true) +////////////////////// +// LLScreenChannelBase +////////////////////// +LLScreenChannelBase::LLScreenChannelBase(const LLUUID& id) : + mOverflowToastPanel(NULL) + ,mToastAlignment(NA_BOTTOM) + ,mCanStoreToasts(true) + ,mHiddenToastsNum(0) + ,mOverflowToastHidden(false) + ,mIsHovering(false) + ,mControlHovering(false) + ,mShowToasts(false) { mID = id; mOverflowFormatString = LLTrans::getString("OverflowInfoChannelString"); - mWorldViewRectConnection = gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLScreenChannel::updatePositionAndSize, this, _1, _2)); + mWorldViewRectConnection = gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLScreenChannelBase::updatePositionAndSize, this, _1, _2)); setMouseOpaque( false ); setVisible(FALSE); } - -//-------------------------------------------------------------------------- -void LLScreenChannel::init(S32 channel_left, S32 channel_right) -{ - S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); - S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); - setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); - setVisible(TRUE); -} - -//-------------------------------------------------------------------------- -LLScreenChannel::~LLScreenChannel() +LLScreenChannelBase::~LLScreenChannelBase() { mWorldViewRectConnection.disconnect(); } - -//-------------------------------------------------------------------------- -void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) +void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) { S32 top_delta = old_world_rect.mTop - new_world_rect.mTop; S32 right_delta = old_world_rect.mRight - new_world_rect.mRight; @@ -105,6 +99,42 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo } setRect(this_rect); redrawToasts(); + +} + +void LLScreenChannelBase::init(S32 channel_left, S32 channel_right) +{ + S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); + S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); + setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); + setVisible(TRUE); +} + +//-------------------------------------------------------------------------- +////////////////////// +// LLScreenChannel +////////////////////// +//-------------------------------------------------------------------------- +LLScreenChannel::LLScreenChannel(LLUUID& id): LLScreenChannelBase(id) +{ +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::init(S32 channel_left, S32 channel_right) +{ + LLScreenChannelBase::init(channel_left, channel_right); +} + +//-------------------------------------------------------------------------- +LLScreenChannel::~LLScreenChannel() +{ + +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) +{ + LLScreenChannelBase::updatePositionAndSize(old_world_rect, new_world_rect); } //-------------------------------------------------------------------------- @@ -561,7 +591,7 @@ void LLScreenChannel::removeAndStoreAllStorableToasts() else { ++it; - } + } } redrawToasts(); } diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index f1ef6bd64d..459c28ac7c 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -55,10 +55,95 @@ typedef enum e_channel_alignment CA_RIGHT, } EChannelAlignment; +class LLScreenChannelBase : public LLUICtrl +{ + friend class LLChannelManager; +public: + LLScreenChannelBase(const LLUUID& id); + ~LLScreenChannelBase(); + + // Channel's outfit-functions + // update channel's size and position in the World View + virtual void updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); + // initialization of channel's shape and position + virtual void init(S32 channel_left, S32 channel_right); + + + virtual void setToastAlignment(EToastAlignment align) {mToastAlignment = align;} + + virtual void setChannelAlignment(EChannelAlignment align) {mChannelAlignment = align;} + virtual void setOverflowFormatString ( const std::string& str) { mOverflowFormatString = str; } + + // kill or modify a toast by its ID + virtual void killToastByNotificationID(LLUUID id) {}; + virtual void modifyToastNotificationByID(LLUUID id, LLSD data) {}; + + // hide all toasts from screen, but not remove them from a channel + virtual void hideToastsFromScreen() {}; + // removes all toasts from a channel + virtual void removeToastsFromChannel() {}; + + // show all toasts in a channel + virtual void redrawToasts() {}; + + virtual void closeOverflowToastPanel() {}; + virtual void hideOverflowToastPanel() {}; + + + // Channel's behavior-functions + // set whether a channel will control hovering inside itself or not + virtual void setControlHovering(bool control) { mControlHovering = control; } + // set Hovering flag for a channel + virtual void setHovering(bool hovering) { mIsHovering = hovering; } + + void setCanStoreToasts(bool store) { mCanStoreToasts = store; } + + void setDisplayToastsAlways(bool display_toasts) { mDisplayToastsAlways = display_toasts; } + bool getDisplayToastsAlways() { return mDisplayToastsAlways; } + + // get number of hidden notifications from a channel + S32 getNumberOfHiddenToasts() { return mHiddenToastsNum;} + + + void setShowToasts(bool show) { mShowToasts = show; } + bool getShowToasts() { return mShowToasts; } + + // get toast allignment preset for a channel + e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} + + // get ID of a channel + LLUUID getChannelID() { return mID; } + +protected: + // Channel's flags + bool mControlHovering; + bool mIsHovering; + bool mCanStoreToasts; + bool mDisplayToastsAlways; + bool mOverflowToastHidden; + // controls whether a channel shows toasts or not + bool mShowToasts; + // + EToastAlignment mToastAlignment; + EChannelAlignment mChannelAlignment; + + // attributes for the Overflow Toast + S32 mHiddenToastsNum; + LLToast* mOverflowToastPanel; + std::string mOverflowFormatString; + + // channel's ID + LLUUID mID; + + // store a connection to prevent futher crash that is caused by sending a signal to a destroyed channel + boost::signals2::connection mWorldViewRectConnection; +}; + + /** * Screen channel manages toasts visibility and positioning on the screen. */ -class LLScreenChannel : public LLUICtrl +class LLScreenChannel : public LLScreenChannelBase { friend class LLChannelManager; public: @@ -70,12 +155,6 @@ public: void updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); // initialization of channel's shape and position void init(S32 channel_left, S32 channel_right); - // set allignment of toasts inside a channel - void setToastAlignment(EToastAlignment align) {mToastAlignment = align;} - // set allignment of channel inside a world view - void setChannelAlignment(EChannelAlignment align) {mChannelAlignment = align;} - // set a template for a string in the OverflowToast - void setOverflowFormatString ( std::string str) { mOverflowFormatString = str; } // Operating with toasts // add a toast to a channel @@ -104,37 +183,17 @@ public: // close the StartUp Toast void closeStartUpToast(); - // Channel's behavior-functions - // set whether a channel will control hovering inside itself or not - void setControlHovering(bool control) { mControlHovering = control; } - // set Hovering flag for a channel - void setHovering(bool hovering) { mIsHovering = hovering; } - // set whether a channel will store faded toasts or not - void setCanStoreToasts(bool store) { mCanStoreToasts = store; } - // tell all channels that the StartUp toast was shown and allow them showing of toasts - static void setStartUpToastShown() { mWasStartUpToastShown = true; } // get StartUp Toast's state static bool getStartUpToastShown() { return mWasStartUpToastShown; } - // set mode for dislaying of toasts - void setDisplayToastsAlways(bool display_toasts) { mDisplayToastsAlways = display_toasts; } - // get mode for dislaying of toasts - bool getDisplayToastsAlways() { return mDisplayToastsAlways; } - // tell a channel to show toasts or not - void setShowToasts(bool show) { mShowToasts = show; } - // determine whether channel shows toasts or not - bool getShowToasts() { return mShowToasts; } + // tell all channels that the StartUp toast was shown and allow them showing of toasts + static void setStartUpToastShown() { mWasStartUpToastShown = true; } // let a channel update its ShowToast flag void updateShowToastsState(); + // Channel's other interface functions functions - // get number of hidden notifications from a channel - S32 getNumberOfHiddenToasts() { return mHiddenToastsNum;} // update number of notifications in the StartUp Toast void updateStartUpString(S32 num); - // get toast allignment preset for a channel - e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} - // get ID of a channel - LLUUID getChannelID() { return mID; } // Channel's signals // signal on storing of faded toasts event @@ -201,30 +260,10 @@ private: // Channel's flags static bool mWasStartUpToastShown; - bool mControlHovering; - bool mIsHovering; - bool mCanStoreToasts; - bool mDisplayToastsAlways; - bool mOverflowToastHidden; - // controls whether a channel shows toasts or not - bool mShowToasts; - // - EToastAlignment mToastAlignment; - EChannelAlignment mChannelAlignment; - - // attributes for the Overflow Toast - S32 mHiddenToastsNum; - LLToast* mOverflowToastPanel; - std::string mOverflowFormatString; // attributes for the StartUp Toast LLToast* mStartUpToastPanel; - // channel's ID - LLUUID mID; - - // store a connection to prevent futher crash that is caused by sending a signal to a destroyed channel - boost::signals2::connection mWorldViewRectConnection; std::vector mToastList; std::vector mStoredToastList; diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 381e63f020..2be0aa40d2 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -48,6 +48,7 @@ #include "lliconctrl.h"//for Home tab icon #include "llsidetraypanelcontainer.h" #include "llwindow.h"//for SetCursor +#include "lltransientfloatermgr.h" //#include "llscrollcontainer.h" @@ -248,6 +249,7 @@ LLSideTray::LLSideTray(Params& params) // register handler function to process data from the xml. // panel_name should be specified via "parameter" attribute. commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null)); + LLTransientFloaterMgr::getInstance()->addControlView(this); } @@ -448,13 +450,17 @@ void LLSideTray::reflectCollapseChange() setPanelRect(); if(mCollapsed) + { gFloaterView->setSnapOffsetRight(0); + setFocus(FALSE); + } else + { gFloaterView->setSnapOffsetRight(mMaxBarWidth); + setFocus(TRUE); + } gFloaterView->refresh(); - - setFocus( FALSE ); } void LLSideTray::arrange () diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index d7df258750..b0930cd86d 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -225,22 +225,14 @@ void LLStatusBar::draw() BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (mHideNavbarContextMenu) - { - mHideNavbarContextMenu->buildDrawLabels(); - mHideNavbarContextMenu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, mHideNavbarContextMenu, x, y); - } - + show_navbar_context_menu(this,x,y); return TRUE; } BOOL LLStatusBar::postBuild() { - mHideNavbarContextMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuHolder->addChild(mHideNavbarContextMenu); - gMenuBarView->setRightMouseDownCallback(boost::bind(&LLStatusBar::onMainMenuRightClicked, this, _1, _2, _3, _4)); + gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3)); return TRUE; } @@ -560,11 +552,6 @@ void LLStatusBar::setupDate() } } -void LLStatusBar::onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask) -{ - handleRightMouseDown(x, y, mask); -} - // static void LLStatusBar::onClickStatGraph(void* data) { diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 81a69e9590..d5629e6f1e 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -91,7 +91,6 @@ private: // simple method to setup the part that holds the date void setupDate(); - void onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); static void onCommitSearch(LLUICtrl*, void* data); static void onClickSearch(void* data); static void onClickStatGraph(void* data); @@ -111,8 +110,7 @@ private: S32 mSquareMetersCommitted; LLFrameTimer* mBalanceTimer; LLFrameTimer* mHealthTimer; - LLMenuGL* mHideNavbarContextMenu; - + static std::vector sDays; static std::vector sMonths; static const U32 MAX_DATE_STRING_LENGTH; diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index c1eecf4c12..2206e79c6f 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -108,6 +108,14 @@ BOOL LLSysWellWindow::postBuild() return LLDockableFloater::postBuild(); } +//--------------------------------------------------------------------------------- +void LLSysWellWindow::setMinimized(BOOL minimize) +{ + setVisible(!minimize); + + LLFloater::setMinimized(minimize); +} + //--------------------------------------------------------------------------------- void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type) { @@ -155,10 +163,10 @@ void LLSysWellWindow::addItem(LLSysWellItem::Params p) { handleItemAdded(IT_NOTIFICATION); - reshapeWindow(); + reshapeWindow(); - new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); - new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); + new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); + new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); } else { @@ -226,11 +234,11 @@ void LLSysWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id) //--------------------------------------------------------------------------------- void LLSysWellWindow::initChannel() { - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( + LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); - if(channel) + mChannel = dynamic_cast(channel); + if(mChannel) { - mChannel = channel; mChannel->setOnStoreToastCallback(boost::bind(&LLSysWellWindow::onStoreToast, this, _1, _2)); } else @@ -240,7 +248,7 @@ void LLSysWellWindow::initChannel() } //--------------------------------------------------------------------------------- -void LLSysWellWindow::getEnabledRect(LLRect& rect) +void LLSysWellWindow::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRect(); } @@ -252,7 +260,7 @@ void LLSysWellWindow::toggleWindow() { setDockControl(new LLDockControl( LLBottomTray::getInstance()->getSysWell(), this, - getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getEnabledRect, this, _1))); + getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getAllowedRect, this, _1))); } if(!getVisible()) @@ -404,20 +412,18 @@ bool LLSysWellWindow::isWindowEmpty() //--------------------------------------------------------------------------------- //virtual -void LLSysWellWindow::sessionAdded(const LLUUID& sessionId, - const std::string& name, const LLUUID& otherParticipantId) +void LLSysWellWindow::sessionAdded(const LLUUID& session_id, + const std::string& name, const LLUUID& other_participant_id) { - if (mMessageList->getItemByValue(get_session_value(sessionId)) == NULL) + //*TODO get rid of get_session_value, session_id's are unique, cause performance degradation with lots chiclets (IB) + if (mMessageList->getItemByValue(get_session_value(session_id)) == NULL) { - S32 chicletCounter = 0; - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::sSessionsMap, - sessionId, (LLIMModel::LLIMSession*) NULL); - if (session != NULL) + S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id); + if (chicletCounter > -1) { - chicletCounter = session->mNumUnread; + addIMRow(session_id, chicletCounter, name, other_participant_id); + reshapeWindow(); } - addIMRow(sessionId, chicletCounter, name, otherParticipantId); - reshapeWindow(); } } @@ -491,6 +497,7 @@ LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& switch (im_chiclet_type) { case LLIMChiclet::TYPE_GROUP: + case LLIMChiclet::TYPE_AD_HOC: mChiclet = getChild("group_chiclet"); childSetVisible("p2p_chiclet", false); break; diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index 37a2690a82..203b949715 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -68,6 +68,8 @@ public: void toggleWindow(); /*virtual*/ BOOL canClose() { return FALSE; } /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + // override LLFloater's minimization according to EXT-1216 + /*virtual*/ void setMinimized(BOOL minimize); // Handlers void onItemClick(LLSysWellItem* item); @@ -86,8 +88,8 @@ private: IT_INSTANT_MESSAGE }EItemType; - // gets a rect valid for SysWellWindow's position on a screen (EXT-1111) - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for the SysWellWindow on a screen (EXT-1111) + void getAllowedRect(LLRect& rect); // connect counter and list updaters to the corresponding signals void connectListUpdaterToSignal(std::string notification_type); // init Window's channel diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 97a15759bf..ecaf4fb150 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -167,15 +167,30 @@ void LLToast::tick() } //-------------------------------------------------------------------------- -void LLToast::insertPanel(LLPanel* panel) + +void LLToast::reshapeToPanel() { - LLRect panel_rect, toast_rect; + LLPanel* panel = getPanel(); + if(!panel) + return; + + LLRect panel_rect; panel_rect = panel->getRect(); reshape(panel_rect.getWidth(), panel_rect.getHeight()); panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight()); panel->setRect(panel_rect); + + LLRect toast_rect = getRect(); + toast_rect.setLeftTopAndSize(toast_rect.mLeft,toast_rect.mTop,panel_rect.getWidth(), panel_rect.getHeight()); + setRect(toast_rect); + +} + +void LLToast::insertPanel(LLPanel* panel) +{ addChild(panel); + reshapeToPanel(); } //-------------------------------------------------------------------------- diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 9248747c43..2166351fd0 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -99,6 +99,9 @@ public: // Operating with toasts // insert a panel to a toast void insertPanel(LLPanel* panel); + + void reshapeToPanel(); + // get toast's panel LLPanel* getPanel() { return mPanel; } // enable/disable Toast's Hide button diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index bc9888f4b4..418373e8c6 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -39,6 +39,12 @@ #include +class LLToastPanelBase: public LLPanel +{ +public: + virtual void init(LLSD& data){}; +}; + /** * Base class for all panels that can be added to the toast. * All toast panels should contain necessary logic for representing certain notification diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 671a62962b..12253455a3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7666,6 +7666,19 @@ class LLHelpShowFirstTimeTip : public view_listener_t } }; +void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) +{ + static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_navbar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } + show_navbar_context_menu->buildDrawLabels(); + show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); +} + void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index cf482266d6..dd6aac2dd3 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -52,6 +52,7 @@ void show_debug_menus(); // checks for if menus should be shown first. void toggle_debug_menus(void*); void show_context_menu( S32 x, S32 y, MASK mask ); void show_build_mode_context_menu(S32 x, S32 y, MASK mask); +void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y); BOOL enable_save_into_inventory(void*); void handle_reset_view(); void handle_cut(void*); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index d23f10f880..4a0efbaddc 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3223,9 +3223,9 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans // assume that pickAsync put the results in the back of the mPicks list if(mPicks.size() != 0) { - mLastPick = mPicks.back(); - mLastPick.fetchResults(); - mPicks.pop_back(); + mLastPick = mPicks.back(); + mLastPick.fetchResults(); + mPicks.pop_back(); } else { diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml index 30406cad63..aef5707fd4 100644 --- a/indra/newview/skins/default/xui/en/floater_sys_well.xml +++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml @@ -12,7 +12,7 @@ width="320" min_width="320" height="23" - can_minimize="false" + can_minimize="true" can_tear_off="false" can_resize="false" can_drag_on_left="false" @@ -22,10 +22,10 @@ + height="0" + width="318"/> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 648c3458e0..2c77f61da6 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -128,13 +128,13 @@ function="World.SetAway" /> + layout="topleft"/> + function="World.SetBusy"/> @@ -117,7 +116,6 @@ label="View" layout="topleft" left="0" - tab_stop="false" tool_tip="Shows/Hide Camera controls" top="6" name="camera_btn" @@ -133,7 +131,6 @@ height="20" width="20" left_pad="0" - tab_stop="false" is_toggle="true" picture_style="true" image_selected="toggle_button_selected" diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index c4c8aa24c4..fb4ce436e8 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -28,7 +28,7 @@ width="25" height="25" label="" - follows="top|left" + follows="top|right" image_overlay="BackArrow_Off" tab_stop="false" /> (Loading...)