diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..0b19cae838 --- /dev/null +++ b/.clang-format @@ -0,0 +1,119 @@ +--- +Language: Cpp +# BasedOnStyle: Microsoft +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +... + diff --git a/.gitignore b/.gitignore index 8bc8c43adb..27b629a578 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,56 @@ -# WinMerge temp files -*.bak -# Compiled python bytecode -*.pyc -# Emacs temp files -*~ -.*.swp -#OSX image cache file +# By extension *.DS_Store -#*.orig +*.bak +*.diff +*.orig +*.pyc +*.rej +*.swp +*~ + +# Specific paths and/or names LICENSES -indra/.distcc -build-linux-* build-darwin-* -build-vc80/ -build-vc100/ -build-vc120/ -build-vc120-32/ -build-vc120-64/ -indra/build-vc[0-9]* +build-linux-* +build-stamp +build-vc120* +build-vc150* +configure-stamp +debian/files +debian/secondlife-appearance-utility* +debian/secondlife-viewer* +indra/.distcc indra/CMakeFiles +indra/build-vc[0-9]* indra/lib/mono/1.0/*.dll indra/lib/mono/indra/*.dll indra/lib/mono/indra/*.exe indra/lib/mono/indra/*.pdb indra/lib/python/eventlet/ +indra/lib/python/mulib.* indra/llwindow/glh/glh_linear.h indra/newview/app_settings/dictionaries indra/newview/app_settings/mozilla indra/newview/app_settings/mozilla-runtime-* indra/newview/app_settings/mozilla_debug indra/newview/app_settings/static_*.db2 +indra/newview/avatar_icons_cache.txt +indra/newview/avatar_lad.log indra/newview/browser_profile indra/newview/character +indra/newview/dbghelp.dll +indra/newview/filters.xml indra/newview/fmod.dll indra/newview/fmod.log indra/newview/mozilla-theme indra/newview/mozilla-universal-darwin.tgz -indra/newview/res/ll_icon.* +indra/newview/pilot.txt +indra/newview/pilot.xml indra/newview/res-sdl/ll_icon.* +indra/newview/res/ll_icon.* +indra/newview/search_history.txt +indra/newview/teleport_history.txt +indra/newview/typed_locations.txt indra/newview/vivox-runtime indra/server-linux-* indra/temp @@ -45,29 +58,15 @@ indra/test/linden_file.dat indra/test_apps/llmediatest/dependencies/i686-win32 indra/test_apps/terrain_mule/*.dll indra/viewer-linux-* +indra/web/dataservice/lib/shared/vault.* +indra/web/dataservice/locale.* +indra/web/dataservice/vendor.* indra/web/doc/asset-upload/plugins/lsl_compiler/lslc indra/web/doc/asset-upload/plugins/verify-notecard indra/web/doc/asset-upload/plugins/verify-texture installed.xml libraries tarfile_tmp -debian/secondlife-viewer* -debian/secondlife-appearance-utility* -debian/files -build-stamp -configure-stamp -indra/newview/dbghelp.dll -*.cpp.orig -*.cpp.bak -*.h.bak -*.h.orig -indra/newview/typed_locations.txt -indra/newview/teleport_history.txt -indra/newview/search_history.txt -indra/newview/filters.xml -indra/newview/avatar_icons_cache.txt -indra/newview/avatar_lad.log -*.diff -indra/newview/pilot.txt -indra/newview/pilot.xml -*.rej +web/config.* +web/locale.* +web/secondlife.com.* \ No newline at end of file diff --git a/autobuild.xml b/autobuild.xml index 47f5fe9d13..513013700e 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3427,7 +3427,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors package_description canonical_repo - https://bitbucket.org/lindenlab/viewer-release + https://bitbucket.org/lindenlab/viewer copyright Copyright (c) 2014, Linden Research, Inc. description diff --git a/build.sh b/build.sh index 1f9daa78b2..e35028ad6e 100755 --- a/build.sh +++ b/build.sh @@ -259,6 +259,23 @@ then export additional_packages= fi +begin_section "select viewer channel" +# Look for a branch-specific viewer_channel setting +# changeset_branch is set in the sling-buildscripts +viewer_build_branch=$(echo -n "${changeset_branch:-$(repo_branch ${BUILDSCRIPTS_SRC:-$(pwd)})}" | tr -Cs 'A-Za-z0-9_' '_' | sed -E 's/^_+//; s/_+$//') +if [ -n "$viewer_build_branch" ] +then + branch_viewer_channel_var="${viewer_build_branch}_viewer_channel" + if [ -n "${!branch_viewer_channel_var}" ] + then + viewer_channel="${!branch_viewer_channel_var}" + record_event "Overriding viewer_channel for branch '$changeset_branch' to '$viewer_channel'" + else + record_event "No branch-specific viewer_channel for branch '$viewer_build_branch'; to set a branch build channel set '$branch_viewer_channel_var'" + fi +fi +end_section "select viewer channel" + python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}" initialize_version # provided by buildscripts build.sh; sets version id diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 89fcbf3ffd..136786c109 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -56,7 +56,7 @@ struct WearableEntry : public LLDictionaryEntry BOOL mAllowMultiwear; }; -class LLWearableDictionary : public LLParamSingleton, +class LLWearableDictionary : public LLSingleton, public LLDictionary { LLSINGLETON(LLWearableDictionary); @@ -70,6 +70,12 @@ protected: LLWearableDictionary::LLWearableDictionary() { + if (!LLWearableType::instanceExists()) + { + // LLWearableType is effectively a wrapper around LLWearableDictionary and is used as storage for LLTranslationBridge + // Todo: consider merging LLWearableType and LLWearableDictionary + LL_WARNS() << "Initing LLWearableDictionary without LLWearableType" << LL_ENDL; + } addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); @@ -101,6 +107,7 @@ LLWearableDictionary::LLWearableDictionary() LLWearableType::LLWearableType(LLTranslationBridge* trans) { + // LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded mTrans = trans; } @@ -109,14 +116,6 @@ LLWearableType::~LLWearableType() delete mTrans; } -void LLWearableType::initSingleton() -{ - // To make sure all wrapping functions will crash without initing LLWearableType; - LLWearableDictionary::initParamSingleton(); - - // Todo: consider merging LLWearableType and LLWearableDictionary -} - // static LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name) { diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 80bb9a10b4..5fe969822a 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -47,7 +47,6 @@ class LLWearableType : public LLParamSingleton LLSINGLETON(LLWearableType, LLTranslationBridge* trans); ~LLWearableType(); friend struct WearableEntry; - void initSingleton(); public: enum EType { diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 78b1483810..85197d1272 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -664,12 +664,14 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie return result; } -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +void LLPluginClassMedia::scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); message.setValueS32("x", x); message.setValueS32("y", y); + message.setValueS32("clicks_x", clicks_x); + message.setValueS32("clicks_y", clicks_y); message.setValue("modifiers", translateModifiers(modifiers)); sendMessage(message); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4f52afb317..9d11ee0421 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,7 +118,7 @@ public: bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - void scrollEvent(int x, int y, MASK modifiers); + void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); // enable/disable media plugin debugging messages and info spam void enableMediaPluginDebugging( bool enable ); diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index 4eb0203245..801b945806 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -1650,7 +1650,7 @@ LLPointer LLRender2D::getUIImage(const std::string& name, S32 priorit // static void LLRender2D::resetProvider() { - if (LLRender2D::instanceExists) + if (LLRender2D::instanceExists()) { LLRender2D::getInstance()->mImageProvider = NULL; } diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index eee6339caf..6a51c4240b 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -47,10 +47,18 @@ static LLDefaultChildRegistry::Register r("check_box"); template class LLCheckBoxCtrl* LLView::getChild( const std::string& name, BOOL recurse) const; +void LLCheckBoxCtrl::WordWrap::declareValues() +{ + declare("none", EWordWrap::WRAP_NONE); + declare("down", EWordWrap::WRAP_DOWN); + declare("up", EWordWrap::WRAP_UP); +} + LLCheckBoxCtrl::Params::Params() : initial_value("initial_value", false), label_text("label_text"), check_button("check_button"), + word_wrap("word_wrap", EWordWrap::WRAP_NONE), radio_style("radio_style") {} @@ -59,14 +67,14 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) : LLUICtrl(p), mTextEnabledColor(p.label_text.text_color()), mTextDisabledColor(p.label_text.text_readonly_color()), - mFont(p.font()) + mFont(p.font()), + mWordWrap(p.word_wrap) { mViewModel->setValue(LLSD(p.initial_value)); mViewModel->resetDirty(); static LLUICachedControl llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); static LLUICachedControl llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); static LLUICachedControl llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); - static LLUICachedControl llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); // must be big enough to hold all children setUseBoundingRect(TRUE); @@ -85,20 +93,47 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) { tbparams.font(p.font); } - mLabel = LLUICtrlFactory::create (tbparams); + + mLabel = LLUICtrlFactory::create(tbparams); + if (mWordWrap != WRAP_NONE) + { + // Not setWordWrap(mWordWrap != WRAP_NONE) because there might be some old lurking code that sets it manually + mLabel->setWordWrap(true); + S32 new_width = getRect().getWidth() - p.check_button.rect().getWidth() - llcheckboxctrl_hpad; + LLRect label_rect = mLabel->getRect(); + label_rect.mRight = label_rect.mLeft + new_width; + mLabel->setRect(label_rect); + } mLabel->reshapeToFitText(); - addChild(mLabel); LLRect label_rect = mLabel->getRect(); + if (mLabel->getLineCount() > 1) + { + if (mWordWrap == WRAP_DOWN) + { + // reshapeToFitText uses LLView::reshape() which always reshapes + // from bottom to top, but we want to extend the bottom + // Note: might be better idea to use getRect().mTop of LLCheckBoxCtrl (+pad) as top point of new rect + S32 delta = ll_round((F32)mLabel->getFont()->getLineHeight() * mLabel->getLineSpacingMult()) - label_rect.getHeight(); + label_rect.translate(0, delta); + mLabel->setRect(label_rect); + } + // else + // WRAP_UP is essentially done by reshapeToFitText() (extends from bottom to top) + // howhever it doesn't respect rect of checkbox + // todo: this should be fixed, but there are at least couple checkboxes that use this feature as is. + } + + addChild(mLabel); // Button - // Note: button cover the label by extending all the way to the right. + // Note: button cover the label by extending all the way to the right and down. LLRect btn_rect = p.check_button.rect(); btn_rect.setOriginAndSize( btn_rect.mLeft, - btn_rect.mBottom, + llmin(btn_rect.mBottom, label_rect.mBottom), llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft), - llmax( label_rect.getHeight(), btn_rect.mTop)); + llmax(label_rect.getHeight(), btn_rect.mTop)); std::string active_true_id, active_false_id; std::string inactive_true_id, inactive_false_id; @@ -152,17 +187,26 @@ void LLCheckBoxCtrl::clear() void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { - + S32 label_top = mLabel->getRect().mTop; mLabel->reshapeToFitText(); LLRect label_rect = mLabel->getRect(); + if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN) + { + // reshapeToFitText uses LLView::reshape() which always reshapes + // from bottom to top, but we want to extend the bottom so + // reposition control + S32 delta = label_top - label_rect.mTop; + label_rect.translate(0, delta); + mLabel->setRect(label_rect); + } // Button - // Note: button cover the label by extending all the way to the right. + // Note: button cover the label by extending all the way to the right and down. LLRect btn_rect = mButton->getRect(); btn_rect.setOriginAndSize( btn_rect.mLeft, - btn_rect.mBottom, + llmin(btn_rect.mBottom, label_rect.mBottom), llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft), llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight())); mButton->setShape(btn_rect); diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 07ae9c3b18..eb5bd5b6da 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -50,6 +50,19 @@ class LLCheckBoxCtrl , public ll::ui::SearchableControl { public: + + enum EWordWrap + { + WRAP_NONE, + WRAP_UP, + WRAP_DOWN + }; + + struct WordWrap : public LLInitParam::TypeValuesHelper + { + static void declareValues(); + }; + struct Params : public LLInitParam::Block { @@ -58,6 +71,8 @@ public: Optional label_text; Optional check_button; + Optional word_wrap; + Ignored radio_style; Params(); @@ -129,6 +144,8 @@ protected: LLUIColor mTextEnabledColor; LLUIColor mTextDisabledColor; + + EWordWrap mWordWrap; // off, shifts text up, shifts text down }; // Build time optimization, generate once in .cpp file diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 200dd2fdca..732fa9feb1 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -788,6 +788,12 @@ void LLMenuItemCallGL::initFromParams(const Params& p) { setEnabledControlVariable(control); } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName() + << ": control " << p.on_enable.control_name() + << " does not exist." << LL_ENDL; + } } } if (p.on_click.isProvided()) diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index a81e115ae2..4446a6e7f4 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore() control("control"), invert_control("invert_control", false), save_option("save_option", false), - session_only("session_only", false) + session_only("session_only", false), + checkbox_only("checkbox_only", false) {} LLNotificationForm::FormButton::FormButton() @@ -195,10 +196,15 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica { if (p.ignore.isProvided()) { + // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences mIgnoreMsg = p.ignore.text; LLUI *ui_inst = LLUI::getInstance(); - if (!p.ignore.save_option) + if (p.ignore.checkbox_only) + { + mIgnore = IGNORE_CHECKBOX_ONLY; + } + else if (!p.ignore.save_option) { mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; } @@ -215,7 +221,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); mInvertSetting = p.ignore.invert_control; } - else + else if (mIgnore > IGNORE_NO) { ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); @@ -389,13 +395,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting() bool LLNotificationForm::getIgnored() { bool show = true; - if (mIgnore != LLNotificationForm::IGNORE_NO + if (mIgnore > LLNotificationForm::IGNORE_NO && mIgnoreSetting) { show = mIgnoreSetting->getValue().asBoolean(); if (mInvertSetting) show = !show; } - return !show; } @@ -696,7 +701,7 @@ void LLNotification::respond(const LLSD& response) mTemporaryResponder = false; } - if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { mForm->setIgnored(mIgnored); if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 9b3d76f47d..269d1c7fa5 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -180,6 +180,7 @@ public: Optional control; Optional invert_control; Optional session_only; + Optional checkbox_only; FormIgnore(); }; @@ -232,7 +233,8 @@ public: typedef enum e_ignore_type { - IGNORE_NO, + IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only + IGNORE_NO = 0, IGNORE_WITH_DEFAULT_RESPONSE, IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY, IGNORE_WITH_LAST_RESPONSE, diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index b3a79bc1eb..fde6de4921 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -408,6 +408,16 @@ BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollbar::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + if (LLScrollbar::HORIZONTAL == mOrientation) + { + handled = changeLine(clicks * mStepSize, TRUE); + } + return handled; +} + BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg) { diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index e2bf52c14b..5f2f490d81 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -88,6 +88,7 @@ public: virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg); diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 6135cc56ad..3db38bbfac 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -272,6 +272,25 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) return FALSE; } +BOOL LLScrollContainer::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLUICtrl::handleScrollHWheel(x,y,clicks)) + { + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollHWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; + } + + return FALSE; +} + BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index e6c7891397..c14099dbd5 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -107,6 +107,7 @@ public: virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f4028057e8..6c8fde580f 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1601,6 +1601,20 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollListCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + // Pretend the mouse is over the scrollbar + handled = mScrollbar->handleScrollHWheel( 0, 0, clicks ); + + if (mMouseWheelOpaque) + { + return TRUE; + } + + return handled; +} + // *NOTE: Requires a valid row_index and column_index LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index) { diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index b35a8608e7..d7572d9fcf 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -317,6 +317,7 @@ public: /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ void setEnabled(BOOL enabled); /*virtual*/ void setFocus( BOOL b ); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 22635f734e..e64078828b 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -3113,6 +3113,7 @@ BOOL LLTextSegment::handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; } +BOOL LLTextSegment::handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; } BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; } const std::string& LLTextSegment::getName() const { diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9831c35858..058b804714 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -103,6 +103,7 @@ public: /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ const std::string& getName() const; /*virtual*/ void onMouseCaptureLost(); @@ -440,6 +441,8 @@ public: S32 getVPad() { return mVPad; } S32 getHPad() { return mHPad; } + F32 getLineSpacingMult() { return mLineSpacingMult; } + S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line = true) const; LLRect getLocalRectFromDocIndex(S32 pos) const; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index df74e113e9..c98da0d410 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -137,13 +137,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.enabled_controls.enabled); if (control) + { setEnabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName() + << ": control " << p.enabled_controls.enabled() + << " does not exist." << LL_ENDL; + } } else if(p.enabled_controls.disabled.isChosen()) { LLControlVariable* control = findControl(p.enabled_controls.disabled); if (control) + { setDisabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName() + << ": control " << p.enabled_controls.disabled() + << " does not exist." << LL_ENDL; + } } } if(p.controls_visibility.isProvided()) @@ -152,13 +168,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.controls_visibility.visible); if (control) + { setMakeVisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign visibility control variable to " << getName() + << ": control " << p.controls_visibility.visible() + << " does not exist." << LL_ENDL; + } } else if (p.controls_visibility.invisible.isChosen()) { LLControlVariable* control = findControl(p.controls_visibility.invisible); if (control) + { setMakeInvisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign invisibility control variable to " << getName() + << ": control " << p.controls_visibility.invisible() + << " does not exist." << LL_ENDL; + } } } @@ -497,6 +529,11 @@ void LLUICtrl::setControlName(const std::string& control_name, LLView *context) if (!control_name.empty()) { LLControlVariable* control = context->findControl(control_name); + if (!control) + { + LL_WARNS() << "Failed to assign control variable to " << getName() + << ": control "<< control_name << " does not exist." << LL_ENDL; + } setControlVariable(control); } } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 55cd45dbf2..593c8b12fc 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1060,6 +1060,11 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleScrollWheel( x, y, clicks ) != NULL; } +BOOL LLView::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleScrollHWheel( x, y, clicks ) != NULL; +} + BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask) { return childrenHandleRightMouseDown( x, y, mask ) != NULL; @@ -1085,6 +1090,11 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false); } +LLView* LLView::childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false); +} + // Called during downward traversal LLView* LLView::childrenHandleKey(KEY key, MASK mask) { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index e36ca7c8c6..db81900aaf 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -426,6 +426,7 @@ public: /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); @@ -556,6 +557,7 @@ protected: LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); + LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks); LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask); diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index d4790f9f29..9397b831f7 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -613,6 +613,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; // CoCreate a IDxDiagProvider* LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -663,9 +664,18 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); @@ -872,6 +882,7 @@ LLSD LLDXHardware::getDisplayInfo() IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; // CoCreate a IDxDiagProvider* LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -922,9 +933,18 @@ LLSD LLDXHardware::getDisplayInfo() hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); @@ -976,6 +996,10 @@ LLSD LLDXHardware::getDisplayInfo() } LCleanup: + if (ret.emptyMap()) + { + LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL; + } SAFE_RELEASE(file_containerp); SAFE_RELEASE(driver_containerp); SAFE_RELEASE(device_containerp); diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index 8e6fbdb4e3..1dcd0348d8 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -66,6 +66,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; virtual BOOL handleToolTip(S32 x, S32 y, MASK mask) = 0; virtual const std::string& getName() const = 0; diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 1b0b9213a5..5b9dce02c4 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -467,7 +467,7 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) scrollWheel:(NSEvent *)theEvent { - callScrollMoved(-[theEvent deltaY]); + callScrollMoved(-[theEvent deltaX], -[theEvent deltaY]); } - (void) mouseExited:(NSEvent *)theEvent diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index c01f574375..be61e1e16c 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -130,6 +130,10 @@ void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) { } +void LLWindowCallbacks::handleScrollHWheel(LLWindow *window, S32 clicks) +{ +} + void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) { } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 9304446f8f..3b18648138 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -56,6 +56,7 @@ public: virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleScrollWheel(LLWindow *window, S32 clicks); + virtual void handleScrollHWheel(LLWindow *window, S32 clicks); virtual void handleResize(LLWindow *window, S32 width, S32 height); virtual void handleFocus(LLWindow *window); virtual void handleFocusLost(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 0f77ebe7a4..44fd4127ce 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -142,7 +142,7 @@ void callDoubleClick(float *pos, unsigned int mask); void callResize(unsigned int width, unsigned int height); void callMouseMoved(float *pos, unsigned int mask); void callMouseDragged(float *pos, unsigned int mask); -void callScrollMoved(float delta); +void callScrollMoved(float deltaX, float deltaY); void callMouseExit(); void callWindowFocus(); void callWindowUnfocus(); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index d9b95d311a..2604a23c85 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -356,9 +356,13 @@ void callMouseDragged(float *pos, MASK mask) gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } -void callScrollMoved(float delta) +void callScrollMoved(float deltaX, float deltaY) { - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta); + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } } void callMouseExit() diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 8fefb119bc..3c69aa98c4 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2662,6 +2662,42 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; } */ + case WM_MOUSEHWHEEL: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEHWHEEL"); + static short h_delta = 0; + + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_h_delta = HIWORD(w_param); + h_delta += incoming_h_delta; + + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) + { + window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA); + h_delta = 0; + } + return 0; + } // Handle mouse movement within the window case WM_MOUSEMOVE: { diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index d5a685e47f..cff21b13c4 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -660,12 +660,18 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_name == "scroll_event") { - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); + // Mouse coordinates for cef to be able to scroll 'containers' + //S32 x = message_in.getValueS32("x"); + //S32 y = message_in.getValueS32("y"); + // Wheel's clicks + S32 delta_x = message_in.getValueS32("clicks_x"); + S32 delta_y = message_in.getValueS32("clicks_y"); const int scaling_factor = 40; - y *= -scaling_factor; + delta_x *= -scaling_factor; + delta_y *= -scaling_factor; - mCEFLib->mouseWheel(x, y); + // mCEFLib->mouseWheel(x, y, delta_x, delta_y); + mCEFLib->mouseWheel(delta_x, delta_y); } else if (message_name == "text_event") { diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f6bafe9d2f..541e206f27 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -244,6 +244,7 @@ set(viewer_SOURCE_FILES llfloaterexperienceprofile.cpp llfloaterexperiences.cpp llfloaterfonttest.cpp + llfloaterforgetuser.cpp llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp @@ -659,6 +660,7 @@ set(viewer_SOURCE_FILES llviewerobject.cpp llviewerobjectlist.cpp llvieweroctree.cpp + llviewerparcelaskplay.cpp llviewerparcelmedia.cpp llviewerparcelmediaautoplay.cpp llviewerparcelmgr.cpp @@ -875,6 +877,7 @@ set(viewer_HEADER_FILES llfloaterexperienceprofile.h llfloaterexperiences.h llfloaterfonttest.h + llfloaterforgetuser.h llfloatergesture.h llfloatergodtools.h llfloatergotoline.h @@ -1284,6 +1287,7 @@ set(viewer_HEADER_FILES llviewerobject.h llviewerobjectlist.h llvieweroctree.h + llviewerparcelaskplay.h llviewerparcelmedia.h llviewerparcelmediaautoplay.h llviewerparcelmgr.h diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index b98d1d3fa7..c44315e3f0 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.3.5 +6.3.7 diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 44bdd33b39..3d6b40c59c 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -158,16 +158,6 @@ is_running_function="Floater.IsOpen" is_running_parameters="moveview" /> - InventoryOutboxDisplayBoth Comment - Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI + (Deprecated) Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI Persist 1 Type @@ -7824,11 +7824,11 @@ ParcelMediaAutoPlayEnable Comment - Auto play parcel media when available + Auto play parcel media when available. 0 - Do not autoplay; 1- Autoplay; 2 - Ask Persist 1 Type - Boolean + S32 Value 1 @@ -8764,6 +8764,17 @@ Value 1 + RememberUser + + Comment + Keep user name for next login + Persist + 1 + Type + Boolean + Value + 1 + RememberPassword Comment @@ -9606,7 +9617,7 @@ RenderShadowResolutionScale Comment - Scale of shadow map resolution vs. screen resolution + Scale of shadow map resolution vs. screen resolution (only positivie values are allowed) Persist 1 Type diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5ec806ea12..f7272da333 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1783,6 +1783,24 @@ void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_ LLInventoryModel::item_array_t* items; LLSD contents = LLSD::emptyArray(); gInventory.getDirectDescendentsOf(src_id, cats, items); + if (!cats || !items) + { + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + LLViewerInventoryCategory* category = gInventory.getCategory(src_id); + if (category) + { + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; + } + else + { + LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; + } + llassert(cats != NULL && items != NULL); + + return; + } + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b4b2723184..5cc53f024b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -68,6 +68,7 @@ #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewermediafocus.h" #include "llviewermessage.h" @@ -682,7 +683,8 @@ LLAppViewer::LLAppViewer() mReportedCrash(false), mNumSessions(0), mPurgeCache(false), - mPurgeOnExit(false), + mPurgeCacheOnExit(false), + mPurgeUserDataOnExit(false), mSecondInstance(false), mSavedFinalSnapshot(false), mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. @@ -1935,6 +1937,11 @@ bool LLAppViewer::cleanup() { gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); LL_INFOS() << "Saved settings" << LL_ENDL; + + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } } std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); @@ -1955,7 +1962,7 @@ bool LLAppViewer::cleanup() LLConversationLog::instance().cache(); } - if (mPurgeOnExit) + if (mPurgeCacheOnExit) { LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*"); @@ -1996,6 +2003,14 @@ bool LLAppViewer::cleanup() } } + if (mPurgeUserDataOnExit) + { + // Ideally we should not save anything from this session since it is going to be purged now, + // but this is a very 'rare' case (user deleting himself), not worth overcomplicating 'save&cleanup' code + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getUserId(); + gDirUtilp->deleteDirAndContents(user_path); + } + // Delete workers first // shotdown all worker threads before deleting them in case of co-dependencies mAppCoreHttp.requestStop(); @@ -4507,7 +4522,7 @@ void LLAppViewer::badNetworkHandler() // Flush all of our caches on exit in the case of disconnect due to // invalid packets. - mPurgeOnExit = TRUE; + mPurgeCacheOnExit = TRUE; std::ostringstream message; message << diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 788fe6a19b..1298ba51e2 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -190,6 +190,7 @@ public: void addOnIdleCallback(const boost::function& cb); // add a callback to fire (once) when idle + void purgeUserDataOnExit() { mPurgeUserDataOnExit = true; } void purgeCache(); // Clear the local cache. void purgeCacheImmediate(); //clear local cache immediately. S32 updateTextureThreads(F32 max_time); @@ -281,7 +282,8 @@ private: std::string mSerialNumber; bool mPurgeCache; - bool mPurgeOnExit; + bool mPurgeCacheOnExit; + bool mPurgeUserDataOnExit; LLViewerJoystick* joystick; bool mSavedFinalSnapshot; diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp index b37aba6c15..4b6c855bde 100644 --- a/indra/newview/llaudiosourcevo.cpp +++ b/indra/newview/llaudiosourcevo.cpp @@ -29,8 +29,10 @@ #include "llaudiosourcevo.h" +#include "llagent.h" #include "llagentcamera.h" #include "llmutelist.h" +#include "llviewercontrol.h" #include "llviewerparcelmgr.h" LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp) @@ -54,6 +56,79 @@ void LLAudioSourceVO::setGain(const F32 gain) mGain = llclamp(gain, 0.f, 1.f); } +void LLAudioSourceVO::checkCutOffRadius() +{ + if (mSourceMuted // already muted by something, will be recalculated on update() + || !mObjectp) + { + return; + } + + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if (cutoff < 0.1f) + { + // consider cutoff below 0.1m as off (to avoid near zero comparison) + return; + } + + LLVector3d pos_global = getPosGlobal(); + if (!isInCutOffRadius(pos_global, cutoff)) + { + mSourceMuted = true; + } +} + +LLVector3d LLAudioSourceVO::getPosGlobal() const +{ + if (mObjectp->isAttachment()) + { + LLViewerObject* parent = mObjectp; + while (parent && !parent->isAvatar()) + { + parent = (LLViewerObject*)parent->getParent(); + } + if (parent) + { + return parent->getPositionGlobal(); + } + } + else + { + return mObjectp->getPositionGlobal(); + } + return LLVector3d(); +} + +bool LLAudioSourceVO::isInCutOffRadius(const LLVector3d pos_global, const F32 cutoff) const +{ + static LLCachedControl ear_mode(gSavedSettings, "VoiceEarLocation", 0); + + LLVector3d pos_ear; + + switch (ear_mode()) + { + case 0: // camera + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + + case 1: // avatar + case 2: + // voice support 'mixed' in '2' case with agent's position and camera's rotations + // but it is not defined in settings and uses camera as default + pos_ear = gAgent.getPositionGlobal(); + break; + + default: + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + } + LLVector3d to_vec = pos_global - pos_ear; + + F32 dist = (F32)to_vec.magVec(); + + return dist < cutoff; +} + void LLAudioSourceVO::updateMute() { if (!mObjectp || mObjectp->isDead()) @@ -63,26 +138,11 @@ void LLAudioSourceVO::updateMute() } bool mute = false; - LLVector3d pos_global; + LLVector3d pos_global = getPosGlobal(); - if (mObjectp->isAttachment()) - { - LLViewerObject* parent = mObjectp; - while (parent && !parent->isAvatar()) - { - parent = (LLViewerObject*)parent->getParent(); - } - if (parent) - { - pos_global = parent->getPositionGlobal(); - } - } - else - { - pos_global = mObjectp->getPositionGlobal(); - } - - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if ((cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) // consider cutoff below 0.1m as off + || !LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) { mute = true; } diff --git a/indra/newview/llaudiosourcevo.h b/indra/newview/llaudiosourcevo.h index f1d8ef4528..672a07f7d3 100644 --- a/indra/newview/llaudiosourcevo.h +++ b/indra/newview/llaudiosourcevo.h @@ -41,7 +41,11 @@ public: /*virtual*/ void update(); /*virtual*/ void setGain(const F32 gain); + void checkCutOffRadius(); + private: + LLVector3d getPosGlobal() const; + bool isInCutOffRadius(LLVector3d pos_global, const F32 cutoff) const; void updateMute(); private: diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 92eeebd705..f0682dc1ba 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -171,7 +171,10 @@ void LLControlAvatar::matchVolumeTransform() if (attached_av) { LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); - setPositionAgent(mRootVolp->getRenderPosition()); + if (getRegion() && !isDead()) + { + setPositionAgent(mRootVolp->getRenderPosition()); + } attach->updateWorldPRSParent(); LLVector3 joint_pos = attach->getWorldPosition(); LLQuaternion joint_rot = attach->getWorldRotation(); @@ -227,7 +230,10 @@ void LLControlAvatar::matchVolumeTransform() #endif setRotation(bind_rot*obj_rot); mRoot->setWorldRotation(bind_rot*obj_rot); - setPositionAgent(vol_pos); + if (getRegion() && !isDead()) + { + setPositionAgent(vol_pos); + } mRoot->setPosition(vol_pos + mPositionConstraintFixup); F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index f7c61efce0..5539fa75dd 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -490,7 +490,7 @@ bool LLConversationLog::saveToFile(const std::string& filename) (S32)conv_it->getConversationType(), (S32)0, (S32)conv_it->hasOfflineMessages(), - conv_it->getConversationName().c_str(), + LLURI::escape(conv_it->getConversationName()).c_str(), participant_id.c_str(), conversation_id.c_str(), LLURI::escape(conv_it->getHistoryFileName()).c_str()); @@ -545,7 +545,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) params.time(LLUnits::Seconds::fromValue(time)) .conversation_type((SessionType)stype) .has_offline_ims(has_offline_ims) - .conversation_name(conv_name_buffer) + .conversation_name(LLURI::unescape(conv_name_buffer)) .participant_id(LLUUID(part_id_buffer)) .session_id(LLUUID(conv_id_buffer)) .history_filename(LLURI::unescape(history_file_name)); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 0075b62100..60a5204547 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -175,7 +175,7 @@ BOOL LLConversationViewSession::postBuild() LLAvatarIconCtrl* icon = mItemPanel->getChild("avatar_icon"); icon->setVisible(true); icon->setValue(session->mOtherParticipantID); - mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true); + mSpeakingIndicator->setSpeakerId(session->mOtherParticipantID, session->mSessionID, true); mHasArrow = false; } break; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 54f29987b8..170e7efa76 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -472,7 +472,7 @@ void LLFace::setTextureIndex(U8 index) } else { - if (mDrawInfo && !mDrawInfo->mTextureList.empty()) + if (mDrawInfo && mDrawInfo->mTextureList.size() <= 1) { LL_ERRS() << "Face with no texture index references indexed texture draw info." << LL_ENDL; } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 5b4b7789b4..17952349dc 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1493,18 +1493,24 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) } // static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) { - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" - + LLGridManager::getInstance()->getGrid() + + grid + ".xml") ); } +// static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); +} + // static void LLFavoritesOrderStorage::destroyClass() { @@ -1602,6 +1608,64 @@ void LLFavoritesOrderStorage::load() } } +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) +{ + std::string filename = getStoredFavoritesFilename(grid); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(user)) + { + LLSD user_llsd = fav_llsd[user]; + + if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"] = iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[user] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; + fav_llsd.erase(user); + } + } + + llofstream out_file; + out_file.open(filename.c_str()); + if (out_file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +// static void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() { std::string filename = getStoredFavoritesFilename(); diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index cac32c7f2a..d93161fd7a 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -208,9 +208,15 @@ public: * @see cleanup() */ static void destroyClass(); + static std::string getStoredFavoritesFilename(const std::string &grid); static std::string getStoredFavoritesFilename(); static std::string getSavedOrderFileName(); + // Remove record of specified user's favorites from file on disk. + static void removeFavoritesRecordOfUser(const std::string &user, const std::string &grid); + // Remove record of current user's favorites from file on disk. + static void removeFavoritesRecordOfUser(); + BOOL saveFavoritesRecord(bool pref_changed = false); void showFavoritesOnLoginChanged(BOOL show); @@ -232,9 +238,6 @@ private: void load(); - // Remove record of current user's favorites from file on disk. - void removeFavoritesRecordOfUser(); - void onLandmarkLoaded(const LLUUID& asset_id, class LLLandmark* landmark); void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index 55561fa128..44725cab70 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -50,6 +50,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i mShowHistory(false), mMessages(NULL), mHistoryThreadsBusy(false), + mIsGroup(false), mOpened(false) { } @@ -75,6 +76,7 @@ BOOL LLFloaterConversationPreview::postBuild() { name = conv->getConversationName(); file = conv->getHistoryFileName(); + mIsGroup = (LLIMModel::LLIMSession::GROUP_SESSION == conv->getConversationType()); } else { @@ -82,6 +84,10 @@ BOOL LLFloaterConversationPreview::postBuild() file = "chat"; } mChatHistoryFileName = file; + if (mIsGroup) + { + mChatHistoryFileName += GROUP_CHAT_SUFFIX; + } LLStringUtil::format_map_t args; args["[NAME]"] = name; std::string title = getString("Title", args); @@ -145,6 +151,7 @@ void LLFloaterConversationPreview::onOpen(const LLSD& key) LLSD load_params; load_params["load_all_history"] = true; load_params["cut_off_todays_date"] = false; + load_params["is_group"] = mIsGroup; // The temporary message list with "Loading..." text // Will be deleted upon loading completion in setPages() method diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index a8dbbc9ffe..7ca4ee6945 100644 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -66,6 +66,7 @@ private: bool mShowHistory; bool mHistoryThreadsBusy; bool mOpened; + bool mIsGroup; }; #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp new file mode 100644 index 0000000000..97b022699f --- /dev/null +++ b/indra/newview/llfloaterforgetuser.cpp @@ -0,0 +1,348 @@ +/** + * @file llfloaterforgetuser.cpp + * @brief LLFloaterForgetUser class definition. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterforgetuser.h" + +#include "llappviewer.h" +#include "llcheckboxctrl.h" +#include "llfavoritesbar.h" +#include "llnotificationsutil.h" +#include "llpanellogin.h" // for helper function getUserName() and to repopulate list if nessesary +#include "llscrolllistctrl.h" +#include "llsecapi.h" +#include "llstartup.h" +#include "llviewercontrol.h" +#include "llviewernetwork.h" + + +LLFloaterForgetUser::LLFloaterForgetUser(const LLSD &key) + : LLFloater("floater_forget_user"), + mLoginPanelDirty(false) +{ + +} + +LLFloaterForgetUser::~LLFloaterForgetUser() +{ + if (mLoginPanelDirty) + { + LLPanelLogin::resetFields(); + } +} + +BOOL LLFloaterForgetUser::postBuild() +{ + mScrollList = getChild("user_list"); + + + bool show_grid_marks = gSavedSettings.getBOOL("ForceShowGrid"); + show_grid_marks |= !LLGridManager::getInstance()->isInProductionGrid(); + + std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); + + if (!show_grid_marks) + { + // Figure out if there are records for more than one grid in storage + for (std::map::iterator grid_iter = known_grids.begin(); + grid_iter != known_grids.end(); + grid_iter++) + { + if (!grid_iter->first.empty() + && grid_iter->first != MAINGRID) // a workaround since 'mIsInProductionGrid' might not be set + { + if (!gSecAPIHandler->emptyCredentialMap("login_list", grid_iter->first)) + { + show_grid_marks = true; + break; + } + + // "Legacy" viewer support + LLPointer cred = gSecAPIHandler->loadCredential(grid_iter->first); + if (cred.notNull()) + { + const LLSD &ident = cred->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + show_grid_marks = true; + break; + } + } + } + } + } + + mUserGridsCount.clear(); + if (!show_grid_marks) + { + // just load maingrid + loadGridToList(MAINGRID, false); + } + else + { + for (std::map::iterator grid_iter = known_grids.begin(); + grid_iter != known_grids.end(); + grid_iter++) + { + if (!grid_iter->first.empty()) + { + loadGridToList(grid_iter->first, true); + } + } + } + + mScrollList->selectFirstItem(); + bool enable_button = mScrollList->getFirstSelectedIndex() != -1; + LLCheckBoxCtrl *chk_box = getChild("delete_data"); + chk_box->setEnabled(enable_button); + chk_box->set(FALSE); + LLButton *button = getChild("forget"); + button->setEnabled(enable_button); + button->setCommitCallback(boost::bind(&LLFloaterForgetUser::onForgetClicked, this)); + + return TRUE; +} + +void LLFloaterForgetUser::onForgetClicked() +{ + LLScrollListCtrl *scroll_list = getChild("user_list"); + LLSD user_data = scroll_list->getSelectedValue(); + const std::string user_id = user_data["user_id"]; + + LLCheckBoxCtrl *chk_box = getChild("delete_data"); + BOOL delete_data = chk_box->getValue(); + + if (delete_data && mUserGridsCount[user_id] > 1) + { + // more than 1 grid uses this id + LLNotificationsUtil::add("LoginRemoveMultiGridUserData", LLSD(), LLSD(), boost::bind(&LLFloaterForgetUser::onConfirmForget, this, _1, _2)); + return; + } + + processForgetUser(); +} + +bool LLFloaterForgetUser::onConfirmForget(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + processForgetUser(); + } + return false; +} + +// static +bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD& response, const std::string &fav_id, const std::string &grid) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + // Remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId()); + + LLPointer cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull() && cred->userID() == LLStartUp::getUserId()) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean favorites + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); + + // mark data for removal + LLAppViewer::instance()->purgeUserDataOnExit(); + LLAppViewer::instance()->requestQuit(); + } + return false; +} + +void LLFloaterForgetUser::processForgetUser() +{ + LLScrollListCtrl *scroll_list = getChild("user_list"); + LLCheckBoxCtrl *chk_box = getChild("delete_data"); + BOOL delete_data = chk_box->getValue(); + LLSD user_data = scroll_list->getSelectedValue(); + const std::string user_id = user_data["user_id"]; + const std::string grid = user_data["grid"]; + const std::string user_name = user_data["label"]; // for favorites + + if (delete_data && user_id == LLStartUp::getUserId() && LLStartUp::getStartupState() > STATE_LOGIN_WAIT) + { + // we can't delete data for user that is currently logged in + // we need to pass grid because we are deleting data universal to grids, but specific grid's user + LLNotificationsUtil::add("LoginCantRemoveCurUsername", LLSD(), LLSD(), boost::bind(onConfirmLogout, _1, _2, user_name, grid)); + return; + } + + // key is used for name of user's folder and in credencials + // user_name is edentical to favorite's username + forgetUser(user_id, user_name, grid, delete_data); + mLoginPanelDirty = true; + if (delete_data) + { + mUserGridsCount[user_id] = 0; //no data left to care about + } + else + { + mUserGridsCount[user_id]--; + } + + // Update UI + scroll_list->deleteSelectedItems(); + scroll_list->selectFirstItem(); + if (scroll_list->getFirstSelectedIndex() == -1) + { + LLButton *button = getChild("forget"); + button->setEnabled(false); + chk_box->setEnabled(false); + } +} + +//static +void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data) +{ + // Remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); + + LLPointer cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull() && cred->userID() == userid) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean data + if (delete_data) + { + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + userid; + gDirUtilp->deleteDirAndContents(user_path); + + // Clean favorites + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(fav_id, grid); + + // Note: we do not clean user-related files from cache because there are id dependent (inventory) + // files and cache has separate cleaning mechanism either way. + // Also this only cleans user from current grid, not all of them. + } +} + +void LLFloaterForgetUser::loadGridToList(const std::string &grid, bool show_grid_name) +{ + std::string grid_label; + if (show_grid_name) + { + grid_label = LLGridManager::getInstance()->getGridId(grid); //login id (shortened label) + } + if (gSecAPIHandler->hasCredentialMap("login_list", grid)) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", grid, credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety + { + std::string user_label = LLPanelLogin::getUserName(cr_iter->second); + LLSD user_data; + user_data["user_id"] = cr_iter->first; + user_data["label"] = user_label; + user_data["grid"] = grid; + + if (show_grid_name) + { + user_label += " (" + grid_label + ")"; + } + + LLScrollListItem::Params item_params; + item_params.value(user_data); + item_params.columns.add() + .value(user_label) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + mScrollList->addRow(item_params, ADD_BOTTOM); + + // Add one to grid count + std::map::iterator found = mUserGridsCount.find(cr_iter->first); + if (found != mUserGridsCount.end()) + { + found->second++; + } + else + { + mUserGridsCount[cr_iter->first] = 1; + } + } + cr_iter++; + } + } + else + { + // "Legacy" viewer support + LLPointer cred = gSecAPIHandler->loadCredential(grid); + if (cred.notNull()) + { + const LLSD &ident = cred->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + std::string user_label = LLPanelLogin::getUserName(cred); + LLSD user_data; + user_data["user_id"] = cred->userID(); + user_data["label"] = user_label; + user_data["grid"] = grid; + + if (show_grid_name) + { + user_label += " (" + grid_label + ")"; + } + + LLScrollListItem::Params item_params; + item_params.value(user_data); + item_params.columns.add() + .value(user_label) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + mScrollList->addRow(item_params, ADD_BOTTOM); + + // Add one to grid count + std::map::iterator found = mUserGridsCount.find(cred->userID()); + if (found != mUserGridsCount.end()) + { + found->second++; + } + else + { + mUserGridsCount[cred->userID()] = 1; + } + } + } + } +} + + diff --git a/indra/newview/llfloaterforgetuser.h b/indra/newview/llfloaterforgetuser.h new file mode 100644 index 0000000000..801fcbb412 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.h @@ -0,0 +1,56 @@ +/** + * @file llfloaterforgetuser.h + * @brief LLFloaterForgetUser class declaration. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERFORGETUSER_H +#define LL_LLFLOATERFORGETUSER_H + +#include "llfloater.h" + +class LLScrollListCtrl; + +class LLFloaterForgetUser : public LLFloater +{ +public: + LLFloaterForgetUser(const LLSD &key); + ~LLFloaterForgetUser(); + + BOOL postBuild(); + void onForgetClicked(); + +private: + bool onConfirmForget(const LLSD& notification, const LLSD& response); + static bool onConfirmLogout(const LLSD& notification, const LLSD& response, const std::string &favorites_id, const std::string &grid); + void processForgetUser(); + static void forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data); + void loadGridToList(const std::string &grid, bool show_grid_name); + + LLScrollListCtrl *mScrollList; + + bool mLoginPanelDirty; + std::map mUserGridsCount; +}; + +#endif diff --git a/indra/newview/llfloatergroupinvite.cpp b/indra/newview/llfloatergroupinvite.cpp index 7fdba8734a..30c90ac184 100644 --- a/indra/newview/llfloatergroupinvite.cpp +++ b/indra/newview/llfloatergroupinvite.cpp @@ -108,7 +108,7 @@ LLFloaterGroupInvite::~LLFloaterGroupInvite() } // static -void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids) +void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids, bool request_update) { const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); S32 floater_header_size = floater_params.header_height; @@ -126,9 +126,12 @@ void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agen group_id, (LLFloaterGroupInvite*)NULL); - // refresh group information - gAgent.sendAgentDataUpdateRequest(); - LLGroupMgr::getInstance()->clearGroupData(group_id); + if (request_update) + { + // refresh group information + gAgent.sendAgentDataUpdateRequest(); + LLGroupMgr::getInstance()->clearGroupData(group_id); + } if (!fgi) diff --git a/indra/newview/llfloatergroupinvite.h b/indra/newview/llfloatergroupinvite.h index f6a3ca5550..657e5711f0 100644 --- a/indra/newview/llfloatergroupinvite.h +++ b/indra/newview/llfloatergroupinvite.h @@ -37,7 +37,7 @@ class LLFloaterGroupInvite public: virtual ~LLFloaterGroupInvite(); - static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL); + static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL, bool request_update = true); protected: LLFloaterGroupInvite(const LLUUID& group_id = LLUUID::null); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 3098c6d118..d8f4360142 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2209,7 +2209,7 @@ void LLPanelLandOptions::refreshSearch() // effort to reduce search spam from small parcels. See also // the search crawler "grid-crawl.py" in secondlife.com/doc/app/search/ JC const S32 MIN_PARCEL_AREA_FOR_SEARCH = 128; - bool large_enough = parcel->getArea() > MIN_PARCEL_AREA_FOR_SEARCH; + bool large_enough = parcel->getArea() >= MIN_PARCEL_AREA_FOR_SEARCH; if (large_enough) { if (can_change) diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 10cce3bd22..595d584799 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -32,6 +32,8 @@ #include "llagent.h" #include "llappearancemgr.h" #include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llnotifications.h" #include "lltextbox.h" #include "llviewercontrol.h" @@ -142,37 +144,72 @@ void LLFloaterLinkReplace::onStartClicked() LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; return; } + + const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); + LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); + const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); + LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - mRemainingInventoryItems, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - if (mRemainingInventoryItems.size() > 0) + LLNotification::Params params("ConfirmReplaceLink"); + params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); + if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) { - LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - if (target_item) + if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) { - mRemainingItems = (U32)mRemainingInventoryItems.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - - mStartBtn->setEnabled(FALSE); - mRefreshBtn->setEnabled(FALSE); - - mEventTimer.start(); - tick(); + LLNotifications::instance().forceResponse(params, 0); } else { - mStatusText->setText(getString("TargetNotFound")); - LL_WARNS() << "Link replace target not found." << LL_ENDL; + LLSD args; + args["TYPE"] = LLWearableType::getTypeName(source_item->getWearableType()); + params.substitutions(args); + LLNotifications::instance().add(params); + } + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} + +void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, const LLSD& response) +{ + + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + mRemainingInventoryItems, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; + + if (mRemainingInventoryItems.size() > 0) + { + LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + if (target_item) + { + mRemainingItems = (U32)mRemainingInventoryItems.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); + + mEventTimer.start(); + tick(); + } + else + { + mStatusText->setText(getString("TargetNotFound")); + LL_WARNS() << "Link replace target not found." << LL_ENDL; + } } } } diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index dd5c301206..060773f93e 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -94,6 +94,7 @@ public: private: void checkEnableStart(); void onStartClicked(); + void onStartClickedResponse(const LLSD& notification, const LLSD& response); void decreaseOpenItemCount(); void updateFoundLinks(); void processBatch(LLInventoryModel::item_array_t items); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c4186132fe..e12ad262f8 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -433,7 +433,7 @@ void LLFloaterModelPreview::initModelPreview() mModelPreview = new LLModelPreview(512, 512, this ); mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); - mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); + mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1)); } void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) @@ -510,7 +510,8 @@ void LLFloaterModelPreview::onClickCalculateBtn() mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); } - mUploadModelUrl.clear(); + mUploadModelUrl.clear(); + mModelPhysicsFee.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, childGetValue("upload_textures").asBoolean(), @@ -4439,6 +4440,12 @@ void LLFloaterModelPreview::toggleCalculateButton() toggleCalculateButton(true); } +void LLFloaterModelPreview::modelUpdated(bool calculate_visible) +{ + mModelPhysicsFee.clear(); + toggleCalculateButton(calculate_visible); +} + void LLFloaterModelPreview::toggleCalculateButton(bool visible) { mCalculateBtn->setVisible(visible); @@ -4464,7 +4471,10 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("download_weight", "[ST]", tbd); childSetTextArg("server_weight", "[SIM]", tbd); childSetTextArg("physics_weight", "[PH]", tbd); - childSetTextArg("upload_fee", "[FEE]", tbd); + if (!mModelPhysicsFee.isMap() || mModelPhysicsFee.emptyMap()) + { + childSetTextArg("upload_fee", "[FEE]", tbd); + } childSetTextArg("price_breakdown", "[STREAMING]", tbd); childSetTextArg("price_breakdown", "[PHYSICS]", tbd); childSetTextArg("price_breakdown", "[INSTANCES]", tbd); @@ -4524,10 +4534,21 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() mUploadBtn->setEnabled(isModelUploadAllowed()); } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) { LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); + + if (result.has("upload_price")) + { + mModelPhysicsFee = result; + childSetTextArg("upload_fee", "[FEE]", llformat("%d", result["upload_price"].asInteger())); + childSetVisible("upload_fee", true); + } + else + { + mModelPhysicsFee.clear(); + } } /*virtual*/ diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index edc90d1695..1c66570650 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -125,7 +125,7 @@ public: /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); - /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason); + /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result); /*virtual*/ void onModelUploadSuccess(); @@ -208,6 +208,8 @@ private: void onLoDSourceCommit(S32 lod); + void modelUpdated(bool calculate_visible); + // Toggles between "Calculate weights & fee" and "Upload" buttons. void toggleCalculateButton(bool visible); diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index 0d4c834122..721fce059e 100644 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -45,7 +45,7 @@ public: virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a6b83f6768..39baa52d90 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -423,6 +423,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); @@ -1245,7 +1246,7 @@ void LLFloaterPreference::buildPopupLists() LLNotificationFormPtr formp = templatep->mForm; LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); - if (ignore == LLNotificationForm::IGNORE_NO) + if (ignore <= LLNotificationForm::IGNORE_NO) continue; LLSD row; @@ -1846,7 +1847,7 @@ void LLFloaterPreference::resetAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(false); } @@ -1859,7 +1860,7 @@ void LLFloaterPreference::setAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(true); } @@ -2279,6 +2280,11 @@ void LLFloaterPreference::onClickPermsDefault() LLFloaterReg::showInstance("perms_default"); } +void LLFloaterPreference::onClickRememberedUsernames() +{ + LLFloaterReg::showInstance("forget_username"); +} + void LLFloaterPreference::onDeleteTranscripts() { LLSD args; @@ -2691,7 +2697,7 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild("enable_music")->get(); bool media_enabled = getChild("enable_media")->get(); - getChild("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index d46f0deb7a..4412c95473 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -168,7 +168,6 @@ public: void refreshUI(); - void onCommitParcelMediaAutoPlayEnable(); void onCommitMediaEnabled(); void onCommitMusicEnabled(); void applyResolution(); @@ -181,6 +180,7 @@ public: void onClickProxySettings(); void onClickTranslationSettings(); void onClickPermsDefault(); + void onClickRememberedUsernames(); void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 50e37170d0..7c41468b77 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -29,6 +29,7 @@ #include "llimprocessing.h" #include "llagent.h" +#include "llappviewer.h" #include "llavatarnamecache.h" #include "llfirstuse.h" #include "llfloaterreg.h" @@ -67,6 +68,8 @@ #pragma warning (disable:4702) #endif +extern void on_new_message(const LLSD& msg); + // Strip out "Resident" for display, but only if the message came from a user // (rather than a script) static std::string clean_name_from_im(const std::string& name, EInstantMessage type) @@ -1120,6 +1123,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + if (message != "") + { + LLSD msg_notify; + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } } @@ -1619,6 +1630,7 @@ void LLIMProcessing::requestOfflineMessages() static BOOL requested = FALSE; if (!requested && gMessageSystem + && !gDisconnected && LLMuteList::getInstance()->isLoaded() && isAgentAvatarValid() && gAgent.getRegion() @@ -1702,6 +1714,12 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) return; } + if (gAgent.getRegion() == NULL) + { + LL_WARNS("Messaging") << "Region null while attempting to load messages." << LL_ENDL; + return; + } + LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; std::vector data; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index abad4d8d73..4ea73ea4d9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -846,7 +846,7 @@ void LLIMModel::LLIMSession::loadHistory() std::list chat_history; //involves parsing of a chat history - LLLogChat::loadChatHistory(mHistoryFileName, chat_history); + LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); addMessagesFromHistory(chat_history); } } @@ -910,6 +910,11 @@ bool LLIMModel::LLIMSession::isP2P() return IM_NOTHING_SPECIAL == mType; } +bool LLIMModel::LLIMSession::isGroupChat() +{ + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID)); +} + bool LLIMModel::LLIMSession::isOtherParticipantAvaline() { return !mOtherParticipantIsAvatar; @@ -967,6 +972,10 @@ void LLIMModel::LLIMSession::buildHistoryFileName() mHistoryFileName = LLCacheName::buildUsername(mName); } } + else if (isGroupChat()) + { + mHistoryFileName = mName + GROUP_CHAT_SUFFIX; + } } //static diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 2a9e4679a8..79c831ebb6 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -91,6 +91,7 @@ public: bool isOutgoingAdHoc() const; bool isAdHoc(); bool isP2P(); + bool isGroupChat(); bool isOtherParticipantAvaline(); bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 8b189793b5..f5d30034dd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2296,7 +2296,7 @@ public: // Can be destroyed (or moved to trash) BOOL LLFolderBridge::isItemRemovable() const { - if (!get_is_category_removable(getInventoryModel(), mUUID) || isMarketplaceListingsFolder()) + if (!get_is_category_removable(getInventoryModel(), mUUID)) { return FALSE; } @@ -2313,6 +2313,11 @@ BOOL LLFolderBridge::isItemRemovable() const } } + if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) + { + return FALSE; + } + return TRUE; } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 028cd56855..e385483b10 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -295,7 +295,6 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible")) { getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); - getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); } // hide marketplace listing box, unless we are a marketplace panel if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders) diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index a99cb1a9e2..7ea63f7930 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -1128,9 +1128,7 @@ void LLLocationInputCtrl::changeLocationPresentation() //change location presentation only if user does not select/paste anything and //human-readable region name is being displayed - std::string text = mTextEntry->getText(); - LLStringUtil::trim(text); - if(!mTextEntry->hasSelection() && text == mHumanReadableLocation) + if(!mTextEntry->hasSelection() && mTextEntry->getText() == mHumanReadableLocation) { //needs unescaped one LLSLURL slurl; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 453bf17b11..0c64531783 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -67,6 +67,8 @@ const std::string LL_IM_FROM("from"); const std::string LL_IM_FROM_ID("from_id"); const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt"); +const std::string GROUP_CHAT_SUFFIX(" (group)"); + const static char IM_SYMBOL_SEPARATOR(':'); const static std::string IM_SEPARATOR(std::string() + IM_SYMBOL_SEPARATOR + " "); const static std::string NEW_LINE("\n"); @@ -355,7 +357,7 @@ void LLLogChat::saveHistory(const std::string& filename, } // static -void LLLogChat::loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params) +void LLLogChat::loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params, bool is_group) { if (file_name.empty()) { @@ -368,10 +370,25 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ if (!fptr) { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } if (!fptr) { - return; //No previous conversation with this name. + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + return; //No previous conversation with this name. + } } } @@ -1053,12 +1070,28 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list& list); static void getListOfTranscriptBackupFiles(std::vector& list_of_transcriptions); - static void loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params = LLSD()); + static void loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params = LLSD(), bool is_group = false); typedef boost::signals2::signal save_history_signal_t; boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); @@ -196,6 +196,7 @@ protected: virtual ~LLChatLogParser() {}; }; +extern const std::string GROUP_CHAT_SUFFIX; // LLSD map lookup constants extern const std::string LL_IM_TIME; //("time"); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index eca34c0d4d..22cedf450e 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -139,8 +139,11 @@ LLPointer LLLoginHandler::initializeLoginInfo() // so try to load it from the UserLoginInfo result = loadSavedUserLoginInfo(); if (result.isNull()) - { - result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + { + // Since legacy viewer store login info one per grid, newer viewers have to + // reuse same information to remember last user and for compatibility, + // but otherwise login info is stored in separate map in gSecAPIHandler + result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); } return result; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 805c25508f..aa0c7fb73b 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -1294,6 +1294,11 @@ void LLMarketplaceData::setSLMDataFetched(U32 status) } } +bool LLMarketplaceData::isSLMDataFetched() +{ + return mMarketPlaceDataFetched == MarketplaceFetchCodes::MARKET_FETCH_DONE; +} + // Creation / Deletion / Update // Methods publicly called bool LLMarketplaceData::createListing(const LLUUID& folder_id) diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index ec312baca3..fee9225f77 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -204,7 +204,9 @@ public: void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb); void setSLMDataFetched(U32 status); U32 getSLMDataFetched() { return mMarketPlaceDataFetched; } - + + bool isSLMDataFetched(); + // High level create/delete/set Marketplace data: each method returns true if the function succeeds, false if error bool createListing(const LLUUID& folder_id); bool activateListing(const LLUUID& folder_id, bool activate, S32 depth = -1); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b399ab9bc4..0affe8efb4 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -202,11 +202,28 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) { if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE; if (mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); + } return TRUE; } +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLPanel::handleScrollHWheel(x, y, clicks)) return TRUE; + if (mMediaSource && mMediaSource->hasMedia()) + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, clicks, 0, gKeyboard->currentMask(TRUE)); + } + + return TRUE; +} + //////////////////////////////////////////////////////////////////////////////// // virtual BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 11400c8274..958c76f261 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -92,6 +92,7 @@ public: virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); // navigation diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 31e3d408d7..95322cce6d 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2772,7 +2772,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } else @@ -2805,7 +2805,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } } diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 91daead876..ee8b3da6b0 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -603,6 +603,8 @@ BOOL LLPanelStandStopFlying::postBuild() //mStopFlyingButton->setCommitCallback(boost::bind(&LLFloaterMove::setFlyingMode, FALSE)); mStopFlyingButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStopFlyingButtonClick, this)); mStopFlyingButton->setVisible(FALSE); + + gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelStandStopFlying::updatePosition, this)); return TRUE; } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 05c89a8abf..73b7ca5503 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -361,7 +361,7 @@ void LLNetMap::draw() LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; - unknown_relative_z = positions[i].mdV[VZ] == COARSEUPDATE_MAX_Z && + unknown_relative_z = positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; LLWorldMapView::drawAvatar( diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 7f6c065bb9..e9fe493d7e 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -245,11 +245,11 @@ void LLOutputMonitorCtrl::draw() // virtual BOOL LLOutputMonitorCtrl::handleMouseUp(S32 x, S32 y, MASK mask) { - if (mSpeakerId != gAgentID && !mShowParticipantsSpeaking) + if (mSpeakerId != gAgentID) { LLFloaterReg::showInstance("floater_voice_volume", LLSD().with("avatar_id", mSpeakerId)); } - else if(mShowParticipantsSpeaking) + else if (mShowParticipantsSpeaking) { LLFloaterReg::showInstance("chat_voice", LLSD()); } diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 6d0c30fbf3..c0342eef4e 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -764,6 +764,7 @@ void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType t setClassifiedName(c_info->name); setDescription(c_info->description); setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); setPosGlobal(c_info->pos_global); setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 0efb234015..e3d75d5604 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1153,7 +1153,7 @@ void LLPanelGroupMembersSubTab::onInviteMember(void *userdata) void LLPanelGroupMembersSubTab::handleInviteMember() { - LLFloaterGroupInvite::showForGroup(mGroupID); + LLFloaterGroupInvite::showForGroup(mGroupID, NULL, false); } void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e253557797..224cec9650 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -77,6 +77,60 @@ LLPanelLogin *LLPanelLogin::sInstance = NULL; BOOL LLPanelLogin::sCapslockDidNotification = FALSE; BOOL LLPanelLogin::sCredentialSet = FALSE; +// Helper functions + +LLPointer load_user_credentials(std::string &user_key) +{ + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + // user_key should be of "name Resident" format + return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + } + else + { + // legacy (or legacy^2, since it also tries to load from settings) + return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + } +} + +// keys are lower case to be case insensitive so they are not always +// identical to names which retain user input, like: +// "AwEsOmE Resident" -> "awesome_resident" +std::string get_user_key_from_name(const std::string &username) +{ + std::string key = username; + LLStringUtil::trim(key); + LLStringUtil::toLower(key); + if (!LLGridManager::getInstance()->isSystemGrid()) + { + size_t separator_index = username.find_first_of(" "); + if (separator_index == username.npos) + { + // CRED_IDENTIFIER_TYPE_ACCOUNT + return key; + } + } + // CRED_IDENTIFIER_TYPE_AGENT + size_t separator_index = username.find_first_of(" ._"); + std::string first = username.substr(0, separator_index); + std::string last; + if (separator_index != username.npos) + { + last = username.substr(separator_index + 1, username.npos); + LLStringUtil::trim(last); + } + else + { + // ...on Linden grids, single username users as considered to have + // last name "Resident" + // *TODO: Make login.cgi support "account_name" like above + last = "resident"; + } + + key = first + "_" + last; + return key; +} + class LLLoginLocationAutoHandler : public LLCommandHandler { public: @@ -168,6 +222,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), + mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -186,7 +241,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + if (mFirstLoginThisInstall) { buildFromFile( "panel_login_first.xml"); } @@ -206,35 +261,39 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); - LLComboBox* favorites_combo = getChild("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - - LLComboBox* server_choice_combo = getChild("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); + std::string current_grid = LLGridManager::getInstance()->getGrid(); + if (!mFirstLoginThisInstall) + { + LLComboBox* favorites_combo = getChild("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - std::string current_grid = LLGridManager::getInstance()->getGrid(); - std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) - { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) - { - LL_DEBUGS("AppInit")<<"adding "<first<add(grid_choice->second, grid_choice->first); - } - } - server_choice_combo->sortByName(); - LL_DEBUGS("AppInit")<<"adding current "<add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); + LLComboBox* server_choice_combo = getChild("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); + + std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty() && current_grid != grid_choice->first) + { + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); + } + } + server_choice_combo->sortByName(); + + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); + } LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -297,14 +356,30 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, loadLoginPage(); LLComboBox* username_combo(getChild("username_combo")); - username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); + username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::onUserNameTextEnty, this)); // STEAM-14: When user presses Enter with this field in focus, initiate login - username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onUserListCommit, this)); + username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); username_combo->setKeystrokeOnEsc(TRUE); + + if (!mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name = getChild("remember_name"); + remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); + } } void LLPanelLogin::addFavoritesToStartLocation() { + if (mFirstLoginThisInstall) + { + // first login panel has no favorites, just update name length and buttons + std::string user_defined_name = getChild("username_combo")->getSimple(); + mUsernameLength = user_defined_name.length(); + updateLoginButtons(); + return; + } + // Clear the combo. LLComboBox* combo = getChild("start_location_combo"); if (!combo) return; @@ -316,14 +391,14 @@ void LLPanelLogin::addFavoritesToStartLocation() // Load favorites into the combo. std::string user_defined_name = getChild("username_combo")->getSimple(); + LLStringUtil::trim(user_defined_name); LLStringUtil::toLower(user_defined_name); - std::replace(user_defined_name.begin(), user_defined_name.end(), '.', ' '); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + LLGridManager::getInstance()->getGrid() + ".xml"); std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); mUsernameLength = user_defined_name.length(); updateLoginButtons(); - std::string::size_type index = user_defined_name.find(' '); + std::string::size_type index = user_defined_name.find_first_of(" ._"); if (index != std::string::npos) { std::string username = user_defined_name.substr(0, index); @@ -332,6 +407,10 @@ void LLPanelLogin::addFavoritesToStartLocation() { user_defined_name = username; } + else + { + user_defined_name = username + " " + lastname; + } } LLSD fav_llsd; @@ -442,24 +521,6 @@ void LLPanelLogin::giveFocus() } } -// static -void LLPanelLogin::showLoginWidgets() -{ - if (sInstance) - { - // *NOTE: Mani - This may or may not be obselete code. - // It seems to be part of the defunct? reg-in-client project. - sInstance->getChildView("login_widgets")->setVisible( true); - LLMediaCtrl* web_browser = sInstance->getChild("login_html"); - - // *TODO: Append all the usual login parameters, like first_login=Y etc. - std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); - LLUICtrl* username_combo = sInstance->getChild("username_combo"); - username_combo->setFocus(TRUE); - } -} - // static void LLPanelLogin::show(const LLRect &rect, void (*callback)(S32 option, void* user_data), @@ -480,9 +541,54 @@ void LLPanelLogin::show(const LLRect &rect, gFocusMgr.setDefaultKeyboardFocus(sInstance); } +//static +void LLPanelLogin::populateFields(LLPointer credential, bool remember_user, bool remember_psswrd) +{ + if (!sInstance) + { + LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; + return; + } + if (sInstance->mFirstLoginThisInstall) + { + LLUICtrl* remember_check = sInstance->getChild("remember_check"); + remember_check->setValue(remember_psswrd); + // no list to populate + setFields(credential); + } + else + { + sInstance->getChild("remember_name")->setValue(remember_user); + LLUICtrl* remember_password = sInstance->getChild("remember_password"); + remember_password->setValue(remember_psswrd); + remember_password->setEnabled(remember_user); + sInstance->populateUserList(credential); + } +} + +//static +void LLPanelLogin::resetFields() +{ + if (!sInstance) + { + // class not existing at this point might happen since this + // function is used to reset list in case of changes by external sources + return; + } + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; + } + else + { + LLPointer cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred); + } +} + // static -void LLPanelLogin::setFields(LLPointer credential, - BOOL remember) +void LLPanelLogin::setFields(LLPointer credential) { if (!sInstance) { @@ -492,36 +598,43 @@ void LLPanelLogin::setFields(LLPointer credential, sCredentialSet = TRUE; LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; - LLSD identifier = credential->getIdentifier(); - if((std::string)identifier["type"] == "agent") + LLSD identifier = credential.notNull() ? credential->getIdentifier() : LLSD(); + + if(identifier.has("type") && (std::string)identifier["type"] == "agent") { + // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; - if (!lastname.empty() && lastname != "Resident") + if (!lastname.empty() && lastname != "Resident" && lastname != "resident") { // support traditional First Last name SLURLs login_id += " "; login_id += lastname; } - sInstance->getChild("username_combo")->setLabel(login_id); + sInstance->getChild("username_combo")->setLabel(login_id); + sInstance->mUsernameLength = login_id.length(); } - else if((std::string)identifier["type"] == "account") + else if(identifier.has("type") && (std::string)identifier["type"] == "account") { - sInstance->getChild("username_combo")->setLabel((std::string)identifier["account_name"]); + std::string login_id = identifier["account_name"].asString(); + sInstance->getChild("username_combo")->setLabel(login_id); + sInstance->mUsernameLength = login_id.length(); } else { - sInstance->getChild("username_combo")->setLabel(std::string()); + sInstance->getChild("username_combo")->setLabel(std::string()); + sInstance->mUsernameLength = 0; } + sInstance->addFavoritesToStartLocation(); // if the password exists in the credential, set the password field with // a filler to get some stars - LLSD authenticator = credential->getAuthenticator(); + LLSD authenticator = credential.notNull() ? credential->getAuthenticator() : LLSD(); LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; if(authenticator.isMap() && authenticator.has("secret") && - (authenticator["secret"].asString().size() > 0) && remember) + (authenticator["secret"].asString().size() > 0)) { // This is a MD5 hex digest of a password. @@ -535,38 +648,28 @@ void LLPanelLogin::setFields(LLPointer credential, } else { - sInstance->getChild("password_edit")->setValue(std::string()); + sInstance->getChild("password_edit")->setValue(std::string()); + sInstance->mPasswordLength = 0; } - sInstance->getChild("remember_check")->setValue(remember); } - // static void LLPanelLogin::getFields(LLPointer& credential, - BOOL& remember) + bool& remember_user, + bool& remember_psswrd) { if (!sInstance) { LL_WARNS() << "Attempted getFields with no login view shown" << LL_ENDL; return; } - - // load the credential so we can pass back the stored password or hash if the user did - // not modify the password field. - - credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); LLSD identifier = LLSD::emptyMap(); LLSD authenticator = LLSD::emptyMap(); - - if(credential.notNull()) - { - authenticator = credential->getAuthenticator(); - } - std::string username = sInstance->getChild("username_combo")->getValue().asString(); - LLStringUtil::trim(username); + std::string username = sInstance->getChild("username_combo")->getSimple(); std::string password = sInstance->getChild("password_edit")->getValue().asString(); + LLStringUtil::trim(username); LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; // determine if the username is a first/last form or not. @@ -586,6 +689,14 @@ void LLPanelLogin::getFields(LLPointer& credential, authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; authenticator["secret"] = password; } + else + { + credential = load_user_credentials(username); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } else { @@ -597,7 +708,7 @@ void LLPanelLogin::getFields(LLPointer& credential, if (separator_index != username.npos) { last = username.substr(separator_index+1, username.npos); - LLStringUtil::trim(last); + LLStringUtil::trim(last); } else { @@ -625,10 +736,29 @@ void LLPanelLogin::getFields(LLPointer& credential, pass.hex_digest(md5pass); authenticator["secret"] = md5pass; } + else + { + std::string key = first + "_" + last; + LLStringUtil::toLower(key); + credential = load_user_credentials(key); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } } credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); - remember = sInstance->getChild("remember_check")->getValue(); + if (!sInstance->mFirstLoginThisInstall) + { + remember_psswrd = sInstance->getChild("remember_password")->getValue(); + remember_user = sInstance->getChild("remember_name")->getValue(); + } + else + { + remember_psswrd = sInstance->getChild("remember_check")->getValue(); + remember_user = remember_psswrd; // on panel_login_first "remember_check" is named as 'remember me' + } } @@ -641,11 +771,8 @@ BOOL LLPanelLogin::areCredentialFieldsDirty() } else { - std::string username = sInstance->getChild("username_combo")->getValue().asString(); - LLStringUtil::trim(username); - std::string password = sInstance->getChild("password_edit")->getValue().asString(); LLComboBox* combo = sInstance->getChild("username_combo"); - if(combo && combo->isDirty()) + if (combo && combo->getCurrentIndex() == -1 && !combo->getValue().asString().empty()) { return true; } @@ -898,8 +1025,8 @@ void LLPanelLogin::onClickConnect(void *) { sCredentialSet = FALSE; LLPointer cred; - BOOL remember; - getFields(cred, remember); + bool remember_1, remember_2; + getFields(cred, remember_1, remember_2); std::string identifier_type; cred->identifierType(identifier_type); LLSD allowed_credential_types; @@ -952,6 +1079,65 @@ void LLPanelLogin::onClickSignUp(void*) } } +// static +void LLPanelLogin::onUserNameTextEnty(void*) +{ + sInstance->mPasswordModified = true; + sInstance->getChild("password_edit")->setValue(std::string()); + sInstance->mPasswordLength = 0; + sInstance->addFavoritesToStartLocation(); //will call updateLoginButtons() +} + +// static +void LLPanelLogin::onUserListCommit(void*) +{ + if (sInstance) + { + LLComboBox* username_combo(sInstance->getChild("username_combo")); + static S32 ind = -1; + if (ind != username_combo->getCurrentIndex()) + { + std::string user_key = username_combo->getSelectedValue(); + LLPointer cred = gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + setFields(cred); + sInstance->mPasswordModified = false; + } + else + { + std::string pass = sInstance->getChild("password_edit")->getValue().asString(); + if (pass.empty()) + { + sInstance->giveFocus(); + } + else + { + onClickConnect(NULL); + } + } + } +} + +// static +// At the moment only happens if !mFirstLoginThisInstall +void LLPanelLogin::onRememberUserCheck(void*) +{ + if (sInstance && !sInstance->mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name(sInstance->getChild("remember_name")); + LLCheckBoxCtrl* remember_psswrd(sInstance->getChild("remember_password")); + LLComboBox* user_combo(sInstance->getChild("username_combo")); + + bool remember = remember_name->getValue().asBoolean(); + if (user_combo->getCurrentIndex() != -1 && !remember) + { + remember = true; + remember_name->setValue(true); + LLNotificationsUtil::add("LoginCantRemoveUsername"); + } + remember_psswrd->setEnabled(remember); + } +} + // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { @@ -976,12 +1162,37 @@ void LLPanelLogin::updateServer() try { // if they've selected another grid, we should load the credentials - // for that grid and set them to the UI. - if(!sInstance->areCredentialFieldsDirty()) + // for that grid and set them to the UI. But if there were any modifications to + // fields, modifications should carry over. + // Not sure if it should carry over password but it worked like this before login changes + // Example: you started typing in and found that your are under wrong grid, + // you switch yet don't lose anything + if (sInstance->areCredentialFieldsDirty()) { - LLPointer credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - bool remember = sInstance->getChild("remember_check")->getValue(); - sInstance->setFields(credential, remember); + // save modified creds + LLComboBox* user_combo = sInstance->getChild("username_combo"); + LLLineEditor* pswd_edit = sInstance->getChild("password_edit"); + std::string username = user_combo->getSimple(); + LLStringUtil::trim(username); + std::string password = pswd_edit->getValue().asString(); + + // populate dropbox and setFields + // Note: following call is related to initializeLoginInfo() + LLPointer credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential); + + // restore creds + user_combo->setTextEntry(username); + pswd_edit->setValue(password); + sInstance->mUsernameLength = username.length(); + sInstance->mPasswordLength = password.length(); + } + else + { + // populate dropbox and setFields + // Note: following call is related to initializeLoginInfo() + LLPointer credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential); } // update the login panel links @@ -1011,14 +1222,85 @@ void LLPanelLogin::updateLoginButtons() LLButton* login_btn = getChild("connect_btn"); login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); + + if (!mFirstLoginThisInstall) + { + LLComboBox* user_combo = getChild("username_combo"); + LLCheckBoxCtrl* remember_name = getChild("remember_name"); + if (user_combo->getCurrentIndex() != -1) + { + remember_name->setValue(true); + LLCheckBoxCtrl* remember_pass = getChild("remember_password"); + remember_pass->setEnabled(TRUE); + } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user + } } +void LLPanelLogin::populateUserList(LLPointer credential) +{ + LLComboBox* user_combo = getChild("username_combo"); + user_combo->removeall(); + user_combo->clear(); + user_combo->setValue(std::string()); + getChild("password_edit")->setValue(std::string()); + mUsernameLength = 0; + mPasswordLength = 0; + + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety in case of future changes + { + // cr_iter->first == user_id , to be able to be find it in case we select it + user_combo->add(LLPanelLogin::getUserName(cr_iter->second), cr_iter->first, ADD_BOTTOM, TRUE); + } + cr_iter++; + } + + if (credential.isNull() || !user_combo->setSelectedByValue(LLSD(credential->userID()), true)) + { + // selection failed, fields will be mepty + updateLoginButtons(); + } + else + { + setFields(credential); + } + } + else + { + if (credential.notNull()) + { + const LLSD &ident = credential->getIdentifier(); + if (ident.isMap() && ident.has("type")) + { + // this llsd might hold invalid credencial (failed login), so + // do not add to the list, just set field. + setFields(credential); + } + else + { + updateLoginButtons(); + } + } + else + { + updateLoginButtons(); + } + } +} + + void LLPanelLogin::onSelectServer() { // The user twiddled with the grid choice ui. // apply the selection to the grid setting. - LLPointer credential; - LLComboBox* server_combo = getChild("server_combo"); LLSD server_combo_val = server_combo->getSelectedValue(); LL_INFOS("AppInit") << "grid "< &cred) +{ + if (cred.isNull()) + { + return "unknown"; + } + const LLSD &ident = cred->getIdentifier(); + + if (!ident.isMap()) + { + return "unknown"; + } + else if ((std::string)ident["type"] == "agent") + { + std::string second_name = ident["last_name"]; + if (second_name == "resident" || second_name == "Resident") + { + return (std::string)ident["first_name"]; + } + return (std::string)ident["first_name"] + " " + (std::string)ident["last_name"]; + } + else if ((std::string)ident["type"] == "account") + { + return LLCacheName::cleanFullName((std::string)ident["account_name"]); + } + + return "unknown"; +} + diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index c633582d89..c9b8e1b6fc 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -55,9 +55,9 @@ public: void (*callback)(S32 option, void* user_data), void* callback_data); - static void setFields(LLPointer credential, BOOL remember); - - static void getFields(LLPointer& credential, BOOL& remember); + static void populateFields(LLPointer credential, bool remember_user, bool remember_psswrd); + static void resetFields(); + static void getFields(LLPointer& credential, bool& remember_user, bool& remember_psswrd); static BOOL isCredentialSet() { return sCredentialSet; } @@ -72,8 +72,6 @@ public: void setSiteIsAlive( bool alive ); - void showLoginWidgets(); - static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); @@ -88,6 +86,9 @@ public: // called from prefs when initializing panel static bool getShowFavorites(); + // extract name from cred in a format apropriate for username field + static std::string getUserName(LLPointer &cred); + private: friend class LLPanelLoginListener; void addFavoritesToStartLocation(); @@ -95,11 +96,16 @@ private: void onSelectServer(); void onLocationSLURL(); + static void setFields(LLPointer credential); + static void onClickConnect(void*); static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); static void onClickSignUp(void*); + static void onUserNameTextEnty(void*); + static void onUserListCommit(void*); + static void onRememberUserCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); @@ -107,6 +113,7 @@ private: boost::scoped_ptr mListener; void updateLoginButtons(); + void populateUserList(LLPointer credential); void (*mCallback)(S32 option, void *userdata); void* mCallbackData; diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index 2dca55514d..b654e928e2 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -43,6 +43,7 @@ #include "llbutton.h" #include "lltextbox.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerregion.h" #include "llviewermediafocus.h" @@ -83,10 +84,11 @@ LLPanelNearByMedia::LLPanelNearByMedia() { mHoverTimer.stop(); - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable + mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); - gSavedSettings.getControl(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING)->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); + gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this)); mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this)); @@ -177,9 +179,18 @@ BOOL LLPanelNearByMedia::postBuild() void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue) { - // update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + // update mParcelAudioAutoStartMode if "ParcelMediaAutoPlayEnable" changes + S32 value = gSavedSettings.getS32("ParcelMediaAutoPlayEnable"); + mParcelAudioAutoStart = value != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + + LLViewerParcelAskPlay *inst = LLViewerParcelAskPlay::getInstance(); + if (value == 2 && !inst->hasData()) + { + // Init if nessesary + inst->loadSettings(); + } + inst->cancelNotification(); } /*virtual*/ diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index c8c9694651..237ed5cf27 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1659,12 +1659,13 @@ void LLPanelObjectInventory::refresh() //LL_INFOS() << "LLPanelObjectInventory::refresh()" << LL_ENDL; BOOL has_inventory = FALSE; const BOOL non_root_ok = TRUE; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, non_root_ok); - if(node) + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstRootNode(NULL, non_root_ok); + if(node && node->mValid) { LLViewerObject* object = node->getObject(); - if(object && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) - || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))) + if(object && ((selection->getRootObjectCount() == 1) + || (selection->getObjectCount() == 1))) { // determine if we need to make a request. Start with a // default based on if we have inventory at all. diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 961e259947..2ef82d0cf9 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -675,6 +675,12 @@ void LLPanelPlaces::onShowOnMapButtonClicked() } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { + if (mItem.isNull()) + { + LL_WARNS() << "NULL landmark item" << LL_ENDL; + llassert(mItem.notNull()); + return; + } LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID()); if (!landmark) return; diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 8105beae1b..3c74aed734 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -547,17 +547,17 @@ void LLPanelPrimMediaControls::updateShape() switch (mScrollState) { case SCROLL_UP: - media_impl->scrollWheel(0, -1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, -1, MASK_NONE); break; case SCROLL_DOWN: - media_impl->scrollWheel(0, 1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, 1, MASK_NONE); break; case SCROLL_LEFT: - media_impl->scrollWheel(1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); break; case SCROLL_RIGHT: - media_impl->scrollWheel(-1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); break; case SCROLL_NONE: @@ -1134,7 +1134,7 @@ void LLPanelPrimMediaControls::onScrollUp(void* user_data) if(impl) { - impl->scrollWheel(0, -1, MASK_NONE); + impl->scrollWheel(0, 0, 0, -1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) @@ -1151,7 +1151,7 @@ void LLPanelPrimMediaControls::onScrollRight(void* user_data) if(impl) { - impl->scrollWheel(-1, 0, MASK_NONE); + impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // impl->handleKeyHere(KEY_RIGHT, MASK_NONE); } } @@ -1170,7 +1170,7 @@ void LLPanelPrimMediaControls::onScrollLeft(void* user_data) if(impl) { - impl->scrollWheel(1, 0, MASK_NONE); + impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // impl->handleKeyHere(KEY_LEFT, MASK_NONE); } } @@ -1189,7 +1189,7 @@ void LLPanelPrimMediaControls::onScrollDown(void* user_data) if(impl) { - impl->scrollWheel(0, 1, MASK_NONE); + impl->scrollWheel(0, 0, 0, 1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 735eaa423d..58bc049338 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -82,8 +82,11 @@ #include -// "Features" Tab +const F32 DEFAULT_GRAVITY_MULTIPLIER = 1.f; +const F32 DEFAULT_DENSITY = 1000.f; + +// "Features" Tab BOOL LLPanelVolume::postBuild() { // Flexible Objects Parameters @@ -830,7 +833,7 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) // static void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { - //LLPanelObject* self = (LLPanelObject*) userdata; + LLPanelVolume* self = (LLPanelVolume*)userdata; LLComboBox* box = (LLComboBox*) ctrl; if (box) @@ -841,6 +844,19 @@ void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) if (material_name != LEGACY_FULLBRIGHT_DESC) { U8 material_code = LLMaterialTable::basic.getMCode(material_name); + if (self) + { + LLViewerObject* objectp = self->mObject; + if (objectp) + { + objectp->setPhysicsGravity(DEFAULT_GRAVITY_MULTIPLIER); + objectp->setPhysicsFriction(LLMaterialTable::basic.getFriction(material_code)); + //currently density is always set to 1000 serverside regardless of chosen material, + //actual material density should be used here, if this behavior change + objectp->setPhysicsDensity(DEFAULT_DENSITY); + objectp->setPhysicsRestitution(LLMaterialTable::basic.getRestitution(material_code)); + } + } LLSelectMgr::getInstance()->selectionSetMaterial(material_code); } } diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 6792137350..f063d84272 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -140,7 +140,7 @@ void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild("enable_music")->get(); bool media_enabled = getChild("enable_media")->get(); - getChild("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 1533a27469..2f534ac245 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -367,6 +367,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, previewEditor->makePristine(); BOOL modifiable = preview->canModify(preview->mObjectID, preview->getItem()); preview->setEnabled(modifiable); + preview->syncExternal(); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -503,10 +504,6 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync) } editor->makePristine(); - if (sync) - { - syncExternal(); - } const LLInventoryItem* item = getItem(); // save it out to database if (item) @@ -755,6 +752,7 @@ void LLPreviewNotecard::openInExternalEditor() // Start watching file changes. mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1)); + mLiveFile->ignoreNextUpdate(); mLiveFile->addToEventTimer(); // Open it in external editor. diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index d207f3b5b7..69b6b32923 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -464,7 +464,19 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data)=0; + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem)=0; + +public: virtual LLPointer createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator)=0; @@ -474,6 +486,42 @@ public: virtual void saveCredential(LLPointer cred, bool save_authenticator)=0; virtual void deleteCredential(LLPointer cred)=0; + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // returns true if map is empty or does not exist + virtual bool emptyCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // load map of credentials from specific storage + typedef std::map > credential_map_t; + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map)=0; + + // load single username from map of credentials from specific storage + virtual LLPointer loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer cred, + bool save_authenticator)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer cred)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid)=0; }; diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 9ab9e4a1a2..55e49100c3 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -52,6 +52,7 @@ #include "llmachineid.h" +static const std::string DEFAULT_CREDENTIAL_STORAGE = "credential"; // 128 bits of salt data... #define STORE_SALT_SIZE 16 @@ -1533,6 +1534,38 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, mProtectedDataMap[data_type][data_id] = data; } +// persist data in a protected store's map +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data) +{ + if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { + mProtectedDataMap[data_type] = LLSD::emptyMap(); + } + + if (!mProtectedDataMap[data_type].has(data_id) || !mProtectedDataMap[data_type][data_id].isMap()) { + mProtectedDataMap[data_type][data_id] = LLSD::emptyMap(); + } + + mProtectedDataMap[data_type][data_id][map_elem] = data; +} + +// remove data from protected store's map +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem) +{ + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id) && + mProtectedDataMap[data_type][data_id].isMap() && + mProtectedDataMap[data_type][data_id].has(map_elem)) + { + mProtectedDataMap[data_type][data_id].erase(map_elem); + } +} + // // Create a credential object from an identifier and authenticator. credentials are // per grid. @@ -1545,10 +1578,10 @@ LLPointer LLSecAPIBasicHandler::createCredential(const std::string return result; } -// Load a credential from the credential store, given the grid +// Load a credential from default credential store, given the grid LLPointer LLSecAPIBasicHandler::loadCredential(const std::string& grid) { - LLSD credential = getProtectedData("credential", grid); + LLSD credential = getProtectedData(DEFAULT_CREDENTIAL_STORAGE, grid); LLPointer result = new LLSecAPIBasicCredential(grid); if(credential.isMap() && credential.has("identifier")) @@ -1603,7 +1636,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav credential["authenticator"] = cred->getAuthenticator(); } LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; - setProtectedData("credential", cred->getGrid(), credential); + setProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? _writeProtectedData(); @@ -1613,11 +1646,150 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav void LLSecAPIBasicHandler::deleteCredential(LLPointer cred) { LLSD undefVal; - deleteProtectedData("credential", cred->getGrid()); + deleteProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid()); cred->setCredentialData(undefVal, undefVal); _writeProtectedData(); } +// has map of credentials declared as specific storage +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return credential.isMap(); +} + +// returns true if map is empty or does not exist +bool LLSecAPIBasicHandler::emptyCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return !credential.isMap() || credential.size() == 0; +} + +// Load map of credentials from specified credential store, given the grid +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap()) + { + LLSD::map_const_iterator crd_it = credential.beginMap(); + for (; crd_it != credential.endMap(); crd_it++) + { + LLSD::String name = crd_it->first; + const LLSD &link_map = crd_it->second; + LLPointer result = new LLSecAPIBasicCredential(grid); + if (link_map.has("identifier")) + { + LLSD identifier = link_map["identifier"]; + LLSD authenticator; + if (link_map.has("authenticator")) + { + authenticator = link_map["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + credential_map[name] = result; + } + } +} + +LLPointer LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLPointer result = new LLSecAPIBasicCredential(grid); + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap() && credential.has(userkey) && credential[userkey].has("identifier")) + { + LLSD identifier = credential[userkey]["identifier"]; + LLSD authenticator; + if (credential[userkey].has("authenticator")) + { + authenticator = credential[userkey]["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + + return result; +} + +// add item to map of credentials from specific storage +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer cred, bool save_authenticator) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + std::string user_id = cred->userID(); + LLSD credential = LLSD::emptyMap(); + credential["identifier"] = cred->getIdentifier(); + if (save_authenticator) + { + credential["authenticator"] = cred->getAuthenticator(); + } + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + addToProtectedMap(storage, cred->getGrid(), user_id, credential); + + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer cred) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + removeFromProtectedMap(storage, cred->getGrid(), cred->userID()); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + LLPointer cred = loadFromCredentialMap(storage, grid, userkey); + removeFromProtectedMap(storage, grid, userkey); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) +{ + deleteProtectedData(storage, grid); + _writeProtectedData(); +} + // load the legacy hash for agni, and decrypt it given the // mac address std::string LLSecAPIBasicHandler::_legacyLoadPassword() @@ -1656,15 +1828,18 @@ std::string LLSecAPIBasicCredential::userID() const } else if ((std::string)mIdentifier["type"] == "agent") { - return (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + std::string id = (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + LLStringUtil::toLower(id); + return id; } else if ((std::string)mIdentifier["type"] == "account") { - return (std::string)mIdentifier["account_name"]; + std::string id = (std::string)mIdentifier["account_name"]; + LLStringUtil::toLower(id); + return id; } return "unknown"; - } // return a printable user identifier diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index c35617f564..0bc7f5230f 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -211,8 +211,9 @@ class LLSecAPIBasicCredential : public LLCredential public: LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} virtual ~LLSecAPIBasicCredential() {} - // return a value representing the user id, (could be guid, name, whatever) - virtual std::string userID() const; + // return a value representing the user id, used for server and voice + // (could be guid, name in format "name_resident", whatever) + virtual std::string userID() const; // printible string identifying the credential. virtual std::string asString() const; @@ -246,7 +247,10 @@ public: // exists, it'll be loaded. If not, one will be created (but not // persisted) virtual LLPointer getCertificateStore(const std::string& store_id); - + + // protectedData functions technically should be pretected or private, + // they are not because of llsechandler_basic_test imlementation + // persist data in a protected store virtual void setProtectedData(const std::string& data_type, const std::string& data_id, @@ -259,19 +263,68 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id); - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data); + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem); + // credential management routines virtual LLPointer createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator); - + + // load single credencial from default storage virtual LLPointer loadCredential(const std::string& grid); + // save credencial to default storage virtual void saveCredential(LLPointer cred, bool save_authenticator); virtual void deleteCredential(LLPointer cred); - + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid); + + // returns true if map is empty or does not exist + virtual bool emptyCredentialMap(const std::string& storage, + const std::string& grid); + + // load map of credentials from specific storage + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map); + + // load single username from map of credentials from specific storage + virtual LLPointer loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer cred, + bool save_authenticator); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer cred); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid); + + protected: void _readProtectedData(); void _writeProtectedData(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 6a2e7a35c0..f93a81fb56 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5506,7 +5506,7 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data } else { - if (node->mInventorySerial != inv_serial) + if (node->mInventorySerial != inv_serial && node->getObject()) { node->getObject()->dirtyInventory(); } diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 8fef3ff1c0..b448caeb0b 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -63,6 +63,7 @@ F32 SHINE_WIDTH = 0.6f; F32 SHINE_OPACITY = 0.3f; F32 FALL_TIME = 0.6f; S32 BORDER_WIDTH = 6; +S32 TOP_PANEL_HEIGHT = 30; const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 @@ -293,8 +294,8 @@ void LLSnapshotLivePreview::draw() F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f); F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f); gGL.pushMatrix(); - { - gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); + { + gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom + TOP_PANEL_HEIGHT, 0.f); gGL.begin(LLRender::QUADS); { gGL.texCoord2f(uv_width, uv_height); @@ -346,14 +347,15 @@ void LLSnapshotLivePreview::draw() F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); // draw "shine" effect - LLLocalClipRect clip(getLocalRect()); + LLRect local_rect(0, getRect().getHeight() + TOP_PANEL_HEIGHT, getRect().getWidth(), 0); + LLLocalClipRect clip(local_rect); { // draw diagonal stripe with gradient that passes over screen S32 x1 = gViewerWindow->getWindowWidthScaled() * ll_round((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); S32 x2 = x1 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); S32 x3 = x2 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); S32 y1 = 0; - S32 y2 = gViewerWindow->getWindowHeightScaled(); + S32 y2 = gViewerWindow->getWindowHeightScaled() + TOP_PANEL_HEIGHT; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::QUADS); @@ -383,36 +385,6 @@ void LLSnapshotLivePreview::draw() } } - // draw framing rectangle - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - const LLRect& outline_rect = getImageRect(); - gGL.begin(LLRender::QUADS); - { - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - } - gGL.end(); - } - // draw old image dropping away if (mFallAnimTimer.getStarted()) { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index b9b74059cc..19172bf860 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -158,6 +158,7 @@ #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -239,7 +240,8 @@ LLSLURL LLStartUp::sStartSLURL; static LLPointer gUserCredential; static std::string gDisplayName; -static BOOL gRememberPassword = TRUE; +static bool gRememberPassword = true; +static bool gRememberUser = true; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; @@ -353,13 +355,6 @@ bool idle_startup() gIdleCallbacks.callFunctions(); gViewerWindow->updateUI(); - // There is a crash on updateClass, this is an attempt to get more information - if (LLMortician::graveyardCount()) - { - std::stringstream log_stream; - LLMortician::logClass(log_stream); - LL_INFOS() << log_stream.str() << LL_ENDL; - } LLMortician::updateClass(); const std::string delims (" "); @@ -704,19 +699,23 @@ bool idle_startup() else if (gSavedSettings.getBOOL("AutoLogin")) { // Log into last account - gRememberPassword = TRUE; - gSavedSettings.setBOOL("RememberPassword", TRUE); + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); show_connect_box = false; } else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) { // Console provided login&password gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = false; } else { gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = TRUE; } @@ -791,10 +790,7 @@ bool idle_startup() // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names - if (gUserCredential.notNull() && !LLPanelLogin::isCredentialSet()) - { - LLPanelLogin::setFields( gUserCredential, gRememberPassword); - } + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); LLPanelLogin::giveFocus(); // MAINT-3231 Show first run dialog only for Desura viewer @@ -890,7 +886,7 @@ bool idle_startup() { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberPassword); + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); // end TODO // HACK: Try to make not jump on login @@ -902,14 +898,21 @@ bool idle_startup() // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; - // save the credentials - std::string userid = "unknown"; - if(gUserCredential.notNull()) - { - userid = gUserCredential->userID(); - gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); - } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + // save the credentials + std::string userid = "unknown"; + if (gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + if (gRememberUser) + { + gSecAPIHandler->addToCredentialMap("login_list", gUserCredential, gRememberPassword); + // Legacy viewers use this method to store user credentials, newer viewers + // reuse it to be compatible and to remember last session + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); + } + } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; gDebugInfo["LoginName"] = userid; @@ -1448,6 +1451,10 @@ bool idle_startup() // create a container's instance for start a controlling conversation windows // by the voice's events LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } // *Note: this is where gWorldMap used to be initialized. @@ -2741,6 +2748,15 @@ std::string& LLStartUp::getInitialOutfitName() return sInitialOutfit; } +std::string LLStartUp::getUserId() +{ + if (gUserCredential.isNull()) + { + return ""; + } + return gUserCredential->userID(); +} + // Loads a bitmap to display during load void init_start_screen(S32 location_id) { diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index db37207022..5ce74b8fae 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -115,6 +115,7 @@ public: static void saveInitialOutfit(); static std::string& getInitialOutfitName(); + static std::string getUserId(); static bool dispatchURL(); // if we have a SLURL or sim string ("Ahern/123/45") that started diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 941cb410fc..f882fd31ee 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -34,7 +34,6 @@ #include "llfontgl.h" #include "lltextbox.h" #include "llbutton.h" -#include "llcheckboxctrl.h" #include "llkeyboard.h" #include "llfocusmgr.h" #include "lliconctrl.h" @@ -62,9 +61,8 @@ static const S32 HPAD = 25; static const S32 BTN_HPAD = 8; LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) - : LLToastPanel(notification), + : LLCheckBoxToastPanel(notification), mDefaultOption( 0 ), - mCheck(NULL), mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), mLabel(notification->getName()), mLineEditor(NULL) @@ -347,20 +345,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal button_left += button_width + BTN_HPAD; } - std::string ignore_label; - - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); - } - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label); - } - else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); - } + setCheckBoxes(HPAD, VPAD); // *TODO: check necessity of this code //gFloaterView->adjustToFitScreen(this, FALSE); @@ -380,46 +365,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal LLTransientFloaterMgr::GLOBAL, this); } -bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control ) -{ - mCheck = LLUICtrlFactory::getInstance()->createFromFile("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); - - if(!mCheck) - { - return false; - } - - const LLFontGL* font = mCheck->getFont(); - const S32 LINE_HEIGHT = font->getLineHeight(); - - std::vector lines; - boost::split(lines, check_title, boost::is_any_of("\n")); - - // Extend dialog for "check next time" - S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD; - S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line - max_msg_width = llmax(max_msg_width, check_width); - S32 dialog_width = max_msg_width + 2 * HPAD; - - S32 dialog_height = LLToastPanel::getRect().getHeight(); - dialog_height += LINE_HEIGHT * lines.size(); - dialog_height += LINE_HEIGHT / 2; - - LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); - - S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; - - // set check_box's attributes - LLRect check_rect; - mCheck->setRect(check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, max_msg_width, LINE_HEIGHT*lines.size())); - mCheck->setLabel(check_title); - mCheck->setCommitCallback(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1)); - - LLToastPanel::addChild(mCheck); - - return true; -} - void LLToastAlertPanel::setVisible( BOOL visible ) { // only make the "ding" sound if it's newly visible @@ -569,16 +514,3 @@ void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button ) mNotification->respond(response); // new notification reponse } - -void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl) -{ - // checkbox sometimes means "hide and do the default" and - // other times means "warn me again". Yuck. JC - BOOL check = ctrl->getValue().asBoolean(); - if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) - { - // question was "show again" so invert value to get "ignore" - check = !check; - } - mNotification->setIgnored(check); -} diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h index 15bf11d42c..9b4e054bf1 100644 --- a/indra/newview/lltoastalertpanel.h +++ b/indra/newview/lltoastalertpanel.h @@ -46,7 +46,7 @@ class LLLineEditor; */ class LLToastAlertPanel - : public LLToastPanel + : public LLCheckBoxToastPanel { LOG_CLASS(LLToastAlertPanel); public: @@ -61,13 +61,11 @@ public: virtual void draw(); virtual void setVisible( BOOL visible ); - bool setCheckBox( const std::string&, const std::string& ); void setCaution(BOOL val = TRUE) { mCaution = val; } // If mUnique==TRUE only one copy of this message should exist void setUnique(BOOL val = TRUE) { mUnique = val; } void setEditTextArgs(const LLSD& edit_args); - void onClickIgnore(LLUICtrl* ctrl); void onButtonPressed(const LLSD& data, S32 button); private: @@ -91,7 +89,6 @@ private: std::vector mButtonData; S32 mDefaultOption; - LLCheckBoxCtrl* mCheck; BOOL mCaution; BOOL mUnique; LLUIString mLabel; diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index a2116817a2..bccf88128d 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -33,6 +33,7 @@ // library includes #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "lllslconstants.h" #include "llnotifications.h" #include "lluiconstants.h" @@ -55,7 +56,7 @@ const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal; LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, const LLRect& rect, bool show_images) -: LLToastPanel(notification), +: LLCheckBoxToastPanel(notification), LLInstanceTracker(notification->getID()) { init(rect, show_images); @@ -162,6 +163,11 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector max_width)// whether there is still some place for button+h_pad in the mControlPanel { // looks like we need to add button to the next row @@ -409,7 +415,20 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) //.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel //can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'. mInfoPanel->setFollowsAll(); - snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + + // Add checkbox (one of couple types) if nessesary. + setCheckBoxes(HPAD * 2, 0, mInfoPanel); + if (mCheck) + { + mCheck->setFollows(FOLLOWS_BOTTOM | FOLLOWS_LEFT); + } + // Snap to message, then to checkbox if present + snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + if (mCheck) + { + S32 new_panel_height = mCheck->getRect().getHeight() + getRect().getHeight() + VPAD; + reshape(getRect().getWidth(), new_panel_height); + } // reshape the panel to its previous size if (current_rect.notEmpty()) diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h index e4a75acfda..a5a637c6fa 100644 --- a/indra/newview/lltoastnotifypanel.h +++ b/indra/newview/lltoastnotifypanel.h @@ -47,7 +47,7 @@ class LLNotificationForm; * @deprecated this class will be removed after all toast panel types are * implemented in separate classes. */ -class LLToastNotifyPanel: public LLToastPanel, public LLInstanceTracker +class LLToastNotifyPanel: public LLCheckBoxToastPanel, public LLInstanceTracker { public: /** diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 2ceec9a23e..6efd667a02 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "llpanelgenerictip.h" #include "llpanelonlinestatus.h" #include "llnotifications.h" @@ -34,6 +35,8 @@ #include "lltoastpanel.h" #include "lltoastscriptquestion.h" +#include + //static const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32) // 'magic numbers', consider initializing (512+20) part from xml/notifications @@ -148,3 +151,108 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification( return res; } + +LLCheckBoxToastPanel::LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf) +: LLToastPanel(p_ntf), +mCheck(NULL) +{ + +} + +void LLCheckBoxToastPanel::setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view) +{ + std::string ignore_label; + LLNotificationFormPtr form = mNotification->getForm(); + + if (form->getIgnoreType() == LLNotificationForm::IGNORE_CHECKBOX_ONLY) + { + // Normally text is only used to describe notification in preferences, + // but this one is not displayed in preferences and works on case by case + // basis. + // Display text if present, display 'always chose' if not. + std::string ignore_message = form->getIgnoreMessage(); + if (ignore_message.empty()) + { + ignore_message = LLNotifications::instance().getGlobalString("alwayschoose"); + } + setCheckBox(ignore_message, ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } +} + +bool LLCheckBoxToastPanel::setCheckBox(const std::string& check_title, + const std::string& check_control, + const commit_signal_t::slot_type& cb, + const S32 &h_pad, + const S32 &v_pad, + LLView *parent_view) +{ + mCheck = LLUICtrlFactory::getInstance()->createFromFile("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); + + if (!mCheck) + { + return false; + } + + const LLFontGL* font = mCheck->getFont(); + const S32 LINE_HEIGHT = font->getLineHeight(); + + std::vector lines; + boost::split(lines, check_title, boost::is_any_of("\n")); + + // Extend dialog for "check next time" + S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * h_pad; + S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line + max_msg_width = llmax(max_msg_width, check_width); + S32 dialog_width = max_msg_width + 2 * h_pad; + + S32 dialog_height = LLToastPanel::getRect().getHeight(); + dialog_height += LINE_HEIGHT * lines.size(); + dialog_height += LINE_HEIGHT / 2; + + LLToastPanel::reshape(dialog_width, dialog_height, FALSE); + + S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; + + // set check_box's attributes + LLRect check_rect; + // if we are part of the toast, we need to leave space for buttons + S32 msg_y = v_pad + (parent_view ? 0 : (BTN_HEIGHT + LINE_HEIGHT / 2)); + mCheck->setRect(check_rect.setOriginAndSize(msg_x, msg_y, max_msg_width, LINE_HEIGHT*lines.size())); + mCheck->setLabel(check_title); + mCheck->setCommitCallback(cb); + + if (parent_view) + { + // assume that width and height autoadjusts to toast + parent_view->addChild(mCheck); + } + else + { + LLToastPanel::addChild(mCheck); + } + + return true; +} + +void LLCheckBoxToastPanel::onCommitCheckbox(LLUICtrl* ctrl) +{ + BOOL check = ctrl->getValue().asBoolean(); + if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 6a9b72a5ae..f4c758ade9 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -64,4 +64,23 @@ protected: S32 computeSnappedToMessageHeight(LLTextBase* message, S32 maxLineCount); }; +class LLCheckBoxCtrl; + +// Wrapper with support for 'don't ask again' checkbox +class LLCheckBoxToastPanel : public LLToastPanel +{ +public: + LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf); + virtual ~LLCheckBoxToastPanel() {}; + + // set checkboxes acording to defaults from form + void setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); + // set single checkbox + bool setCheckBox(const std::string&, const std::string&, const commit_signal_t::slot_type& cb, const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); +protected: + void onCommitCheckbox(LLUICtrl* ctrl); + + LLCheckBoxCtrl* mCheck; +}; + #endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index b5d78f3654..c5e31ff8e6 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -115,6 +115,12 @@ BOOL LLTool::handleScrollWheel(S32 x, S32 y, S32 clicks) return FALSE; } +BOOL LLTool::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + // by default, didn't handle it + return FALSE; +} + BOOL LLTool::handleDoubleClick(S32 x,S32 y,MASK mask) { // LL_INFOS() << "LLTool::handleDoubleClick" << LL_ENDL; diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index c5bad9d532..308983afda 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -57,6 +57,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index b307a013a3..04066ebf95 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1758,6 +1758,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } @@ -2230,6 +2231,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 4f2aaa97c1..ae6547b77e 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -400,7 +400,7 @@ bool LLToolMgr::inBuildMode() bool LLToolMgr::canAccessMarketplace() { - return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT) || gSavedSettings.getBOOL("InventoryOutboxDisplayBoth"); + return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); } void LLToolMgr::toggleMarketplace(const LLSD& sdname) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 4711915d51..214450beba 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -212,6 +212,11 @@ BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); } +BOOL LLToolPie::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} + // True if you selected an object. BOOL LLToolPie::handleLeftClickPick() { diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 677b244e35..373694443f 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -50,6 +50,7 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); virtual void render(); diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 15c3dad38e..77e950a1c9 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -53,7 +53,7 @@ public: virtual ~LLWholeModelFeeObserver() {} virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; LLHandle getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f74d26cd3f..4f828044e8 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -68,6 +68,7 @@ #include "llfloaterexperiencepicker.h" #include "llfloaterevent.h" #include "llfloaterfonttest.h" +#include "llfloaterforgetuser.h" #include "llfloatergesture.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" @@ -235,6 +236,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 3029b14647..872476b6d9 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1813,7 +1813,7 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, { std::string type_name = userdata.asString(); - if (("inbox" == type_name) || ("outbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) + if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) { LLFolderType::EType preferred_type = LLFolderType::lookup(type_name); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 0244e5f1ae..c36e6960b0 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -57,6 +57,7 @@ #include "llviewercontrol.h" #include "llviewermenufile.h" // LLFilePickerThread #include "llviewernetwork.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -1018,6 +1019,8 @@ void LLViewerMedia::setAllMediaPaused(bool val) } } + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Also do Parcel Media and Parcel Audio if (!val) { @@ -1051,6 +1054,12 @@ void LLViewerMedia::setAllMediaPaused(bool val) LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } } + + // remove play choice for current parcel + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::getInstance()->resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2285,14 +2294,14 @@ void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask) { scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; if (mMediaSource) { - mMediaSource->scrollEvent(x, y, mask); + mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask); } } @@ -3757,7 +3766,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id) bool LLViewerMediaImpl::isAutoPlayable() const { return (mMediaAutoPlay && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 && gSavedSettings.getBOOL("MediaTentativeAutoPlay")); } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 014f9048f0..9467a138f0 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -79,7 +79,7 @@ class LLViewerMedia: public LLSingleton public: // String to get/set media autoplay in gSavedSettings - static const char* AUTO_PLAY_MEDIA_SETTING; + static const char* AUTO_PLAY_MEDIA_SETTING; static const char* SHOW_MEDIA_ON_OTHERS_SETTING; static const char* SHOW_MEDIA_WITHIN_PARCEL_SETTING; static const char* SHOW_MEDIA_OUTSIDE_PARCEL_SETTING; @@ -235,7 +235,7 @@ public: void mouseMove(const LLVector2& texture_coords, MASK mask); void mouseDoubleClick(const LLVector2& texture_coords, MASK mask); void mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button = 0); - void scrollWheel(S32 x, S32 y, MASK mask); + void scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask); void mouseCapture(); void navigateBack(); @@ -320,6 +320,7 @@ public: /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index f4a64a8e55..69ab0a71af 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -377,12 +377,7 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); if(media_impl && media_impl->hasMedia()) { - // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. - // The latter is the position of the mouse at the time of the event - // The former is the 'scroll amount' in x and y, respectively. - // All we have for 'scroll amount' here is 'clicks'. - // We're also not passed the keyboard modifier mask, but we can get that from gKeyboard. - media_impl->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + media_impl->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); retval = TRUE; } return retval; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ed5a72a5d4..6ee6c6de7d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -409,23 +409,20 @@ void set_merchant_SLM_menu() void check_merchant_status(bool force) { - if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) + if (force) { - if (force) - { - // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); - } - // Hide SLM related menu item - gMenuHolder->getChild("MarketplaceListings")->setVisible(FALSE); - - // Also disable the toolbar button for Marketplace Listings - LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); - gToolBarView->enableCommand(command->id(), false); - - // Launch an SLM test connection to get the merchant status - LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); } + // Hide SLM related menu item + gMenuHolder->getChild("MarketplaceListings")->setVisible(FALSE); + + // Also disable the toolbar button for Marketplace Listings + LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); + gToolBarView->enableCommand(command->id(), false); + + // Launch an SLM test connection to get the merchant status + LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); } void init_menus() diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 79a6ce44fa..8a26677728 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -391,6 +391,11 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_ LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; if(can_afford_transaction(amount)) { + if (uuid.isNull()) + { + LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; + return; + } // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 65c4278ce8..f1108f9ca5 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -273,6 +273,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), + mSoundCutOffRadius(0.f), mAppAngle(0.f), mPixelArea(1024.f), mInventory(NULL), @@ -1259,6 +1260,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLUUID audio_uuid; LLUUID owner_id; // only valid if audio_uuid or particle system is not null F32 gain; + F32 cutoff; U8 sound_flags; mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); @@ -1267,6 +1269,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // HACK: Owner id only valid if non-null sound id or particle system mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); + mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Radius, cutoff, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); @@ -1275,6 +1278,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE); mTotalCRC = crc; + mSoundCutOffRadius = cutoff; // Owner ID used for sound muting or particle system muting setAttachedSound(audio_uuid, owner_id, gain, sound_flags); @@ -1983,6 +1987,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } mTotalCRC = crc; + mSoundCutOffRadius = cutoff; setAttachedSound(sound_uuid, owner_id, gain, sound_flags); @@ -3027,6 +3032,7 @@ void LLViewerObject::fetchInventoryFromServer() if (!isInventoryPending()) { delete mInventory; + mInventory = NULL; // Results in processTaskInv LLMessageSystem* msg = gMessageSystem; @@ -5957,6 +5963,8 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) { //LL_INFOS() << "Playing attached sound " << audio_uuid << LL_ENDL; + // recheck cutoff radius in case this update was an object-update with new value + mAudioSourcep->checkCutOffRadius(); mAudioSourcep->play(audio_uuid); } } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 056a992e06..809ad995d3 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -409,6 +409,7 @@ public: // Owner id is this object's owner void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); void adjustAudioGain(const F32 gain); + F32 getSoundCutOffRadius() const { return mSoundCutOffRadius; } void clearAttachedSound() { mAudioSourcep = NULL; } // Create if necessary @@ -796,6 +797,7 @@ protected: LLPointer mPartSourcep; // Particle source associated with this object. LLAudioSourceVO* mAudioSourcep; F32 mAudioGain; + F32 mSoundCutOffRadius; F32 mAppAngle; // Apparent visual arc in degrees F32 mPixelArea; // Apparent area in pixels diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp new file mode 100644 index 0000000000..d4aa783f12 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.cpp @@ -0,0 +1,301 @@ +/** + * @file llviewerparcelaskplay.cpp + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llviewerparcelaskplay.h" + +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llstartup.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llsdserialize.h" + +#include + + +// class LLViewerParcelAskPlay + +LLViewerParcelAskPlay::LLViewerParcelAskPlay() : +pNotification(NULL) +{ +} + +LLViewerParcelAskPlay::~LLViewerParcelAskPlay() +{ + +} + +void LLViewerParcelAskPlay::initSingleton() +{ + +} +void LLViewerParcelAskPlay::cleanupSingleton() +{ + cancelNotification(); +} + +void LLViewerParcelAskPlay::askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb) +{ + EAskPlayMode mode = getPlayMode(region_id, parcel_id); + + switch (mode) + { + case ASK_PLAY_IGNORE: + cb(region_id, parcel_id, url, false); + break; + case ASK_PLAY_PLAY: + cb(region_id, parcel_id, url, true); + break; + case ASK_PLAY_ASK: + default: + { + // create or re-create notification + cancelNotification(); + + if (LLStartUp::getStartupState() > STATE_PRECACHE) + { + LLSD args; + args["URL"] = url; + LLSD payload; + payload["url"] = url; // or we can extract it from notification["substitutions"] + payload["parcel_id"] = parcel_id; + payload["region_id"] = region_id; + pNotification = LLNotificationsUtil::add("ParcelPlayingMedia", args, payload, boost::bind(onAskPlayResponse, _1, _2, cb)); + } + else + { + // workaround: avoid 'new notifications arrived' on startup and just play + // (alternative: move to different channel, may be create new one...) + cb(region_id, parcel_id, url, true); + } + } + } +} + +void LLViewerParcelAskPlay::cancelNotification() +{ + if (pNotification) + { + if (!pNotification->isCancelled()) + { + // Force a responce + // Alternative is to mark notification as unique + pNotification->setIgnored(false); + LLNotifications::getInstance()->cancel(pNotification); + } + pNotification = NULL; + } +} + +void LLViewerParcelAskPlay::resetCurrentParcelSetting() +{ + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } +} + +void LLViewerParcelAskPlay::resetSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + found->second.erase(parcel_id); + } +} + +void LLViewerParcelAskPlay::resetSettings() +{ + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->mRegionMap.clear(); + } + LLFile::remove(getAskPlayFilename()); +} + +void LLViewerParcelAskPlay::setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data) +{ + mRegionMap[region_id][parcel_id] = data; +} + +LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + parcel_data_map_t::iterator found_parcel = found->second.find(parcel_id); + if (found_parcel != found->second.end()) + { + return &(found_parcel->second); + } + } + return NULL; +} + +LLViewerParcelAskPlay::EAskPlayMode LLViewerParcelAskPlay::getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id) +{ + EAskPlayMode mode = ASK_PLAY_ASK; + ParcelData* data = getSetting(region_id, parcel_id); + if (data) + { + mode = data->mMode; + // refresh date + data->mDate = LLDate::now(); + } + return mode; +} + +void LLViewerParcelAskPlay::setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, LLViewerParcelAskPlay::EAskPlayMode mode) +{ + ParcelData data; + data.mMode = mode; + data.mDate = LLDate::now(); + setSetting(region_id, parcel_id, data); +} + +//static +void LLViewerParcelAskPlay::onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + LLUUID region_id = notification["payload"]["region_id"]; + S32 parcel_id = notification["payload"]["parcel_id"]; + std::string url = notification["payload"]["url"]; + + bool play = option == 1; + + cb(region_id, parcel_id, url, play); + + LLViewerParcelAskPlay *inst = getInstance(); + bool save_choice = inst->pNotification->isIgnored(); // checkbox selected + if (save_choice) + { + EAskPlayMode mode = (play) ? ASK_PLAY_PLAY : ASK_PLAY_IGNORE; + inst->setPlayMode(region_id, parcel_id, mode); + } +} + +// static +std::string LLViewerParcelAskPlay::getAskPlayFilename() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_autoplay.xml"); +} + +void LLViewerParcelAskPlay::loadSettings() +{ + mRegionMap.clear(); + + std::string path = getAskPlayFilename(); + if (!gDirUtilp->fileExists(path)) + { + return; + } + + LLSD autoplay_llsd; + llifstream file; + file.open(path.c_str()); + if (!file.is_open()) + { + return; + } + S32 status = LLSDSerialize::fromXML(autoplay_llsd, file); + file.close(); + + if (status == LLSDParser::PARSE_FAILURE || !autoplay_llsd.isMap()) + { + return; + } + + for (LLSD::map_const_iterator iter_region = autoplay_llsd.beginMap(); + iter_region != autoplay_llsd.endMap(); ++iter_region) + { + LLUUID region_id = LLUUID(iter_region->first); + mRegionMap[region_id] = parcel_data_map_t(); + + const LLSD &parcel_map = iter_region->second; + + if (parcel_map.isMap()) + { + for (LLSD::map_const_iterator iter_parcel = parcel_map.beginMap(); + iter_parcel != parcel_map.endMap(); ++iter_parcel) + { + if (!iter_parcel->second.isMap()) + { + break; + } + S32 parcel_id = boost::lexical_cast(iter_parcel->first.c_str()); + ParcelData data; + data.mMode = (EAskPlayMode)(iter_parcel->second["mode"].asInteger()); + data.mDate = iter_parcel->second["date"].asDate(); + mRegionMap[region_id][parcel_id] = data; + } + } + } +} + +void LLViewerParcelAskPlay::saveSettings() +{ + LLSD write_llsd; + std::string key; + for (region_map_t::iterator iter_region = mRegionMap.begin(); + iter_region != mRegionMap.end(); ++iter_region) + { + if (iter_region->second.empty()) + { + continue; + } + key = iter_region->first.asString(); + write_llsd[key] = LLSD(); + + for (parcel_data_map_t::iterator iter_parcel = iter_region->second.begin(); + iter_parcel != iter_region->second.end(); ++iter_parcel) + { + if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds()) + { + // write unexpired parcels + std::string parcel_id = boost::lexical_cast(iter_parcel->first); + write_llsd[key][parcel_id] = LLSD(); + write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode; + write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate; + } + } + } + + llofstream file; + file.open(getAskPlayFilename().c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(write_llsd, file); + file.close(); + } +} + diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h new file mode 100644 index 0000000000..dc711917d2 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.h @@ -0,0 +1,89 @@ +/** + * @file llviewerparcelaskplay.h + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLVIEWERPARCELASKPLAY_H +#define LLVIEWERPARCELASKPLAY_H + +#include "llnotificationptr.h" +#include "lluuid.h" + +class LLViewerParcelAskPlay : public LLSingleton +{ + LLSINGLETON(LLViewerParcelAskPlay); + ~LLViewerParcelAskPlay(); + void initSingleton(); + void cleanupSingleton(); +public: + // functor expects functor(region_id, parcel_id, url, play/stop) + typedef boost::function ask_callback; + void askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb); + void cancelNotification(); + + void resetCurrentParcelSetting(); + void resetSetting(const LLUUID ®ion_id, const S32 &parcel_id); + static void resetSettings(); + + void loadSettings(); + void saveSettings(); + + S32 hasData() { return !mRegionMap.empty(); } // subsitution for 'isInitialized' + +private: + enum EAskPlayMode{ + ASK_PLAY_IGNORE = 0, + ASK_PLAY_PLAY, + ASK_PLAY_ASK + }; + + class ParcelData + { + public: + LLDate mDate; + EAskPlayMode mMode; + }; + + void setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const ParcelData &data); + ParcelData* getSetting(const LLUUID ®ion_id, const S32 &parcel_id); + EAskPlayMode getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id); + void setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, EAskPlayMode); + + static void onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb); + + static std::string getAskPlayFilename(); + +private: + // Variables + + typedef std::map parcel_data_map_t; + typedef std::map region_map_t; + region_map_t mRegionMap; + + // only one notification is supposed to exists and be visible + LLNotificationPtr pNotification; +}; + + +#endif // LLVIEWERPARCELASKPLAY_H diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index b5a76ccba2..36c7d436f6 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -24,17 +24,20 @@ * $/LicenseInfo$ */ + #include "llviewerprecompiledheaders.h" + #include "llviewerparcelmediaautoplay.h" -#include "llviewerparcelmedia.h" + +#include "llparcel.h" #include "llviewercontrol.h" #include "llviewermedia.h" -#include "llviewerregion.h" -#include "llparcel.h" +#include "llviewerparcelaskplay.h" +#include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" -#include "lluuid.h" -#include "message.h" +#include "llviewerregion.h" #include "llviewertexturelist.h" // for texture stats +#include "message.h" #include "llagent.h" #include "llmimetypes.h" @@ -122,11 +125,28 @@ BOOL LLViewerParcelMediaAutoPlay::tick() { if (this_parcel) { - if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable")) + static LLCachedControl autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + + switch (autoplay_mode()) { - // and last but not least, only play when autoplay is enabled - LLViewerParcelMedia::getInstance()->play(this_parcel); - } + case 0: + // Disabled + break; + case 1: + // Play, default value for ParcelMediaAutoPlayEnable + LLViewerParcelMedia::getInstance()->play(this_parcel); + break; + case 2: + default: + { + // Ask + LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), + this_parcel->getLocalID(), + this_parcel->getMediaURL(), + onStartMusicResponse); + break; + } + } } mPlayed = TRUE; @@ -139,5 +159,18 @@ BOOL LLViewerParcelMediaAutoPlay::tick() return FALSE; // continue ticking forever please. } +//static +void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) +{ + if (play) + { + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // make sure we are still there + if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id) + { + LLViewerParcelMedia::getInstance()->play(parcel); + } + } +} diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index 33565307f2..cf8e9a97e7 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -38,6 +38,9 @@ public: virtual BOOL tick(); static void playStarted(); + private: + static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + private: S32 mLastParcelID; LLUUID mLastRegionID; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 57d0da6683..67e274ed39 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@ // Viewer includes #include "llagent.h" #include "llagentaccess.h" +#include "llviewerparcelaskplay.h" #include "llviewerwindow.h" #include "llviewercontrol.h" //#include "llfirstuse.h" @@ -1832,6 +1833,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Only update stream if parcel changed (recreated) or music is playing (enabled) if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay")) { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); std::string music_url_raw = parcel->getMusicURL(); // Trim off whitespace from front and back @@ -1843,7 +1845,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { if (music_url.substr(0, 7) == "http://") { - optionally_start_music(music_url); + LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); + optionally_start_music(music_url, parcel->mLocalID, region->getRegionID()); } else { @@ -1864,25 +1867,61 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use else { // Public land has no music + LLViewerParcelAskPlay::getInstance()->cancelNotification(); LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } }//if gAudiop }; } -void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) +//static +void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) { - if (gSavedSettings.getBOOL("AudioStreamingMusic")) + if (play) + { + LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); + } +} + +void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id) +{ + static LLCachedControl streaming_music(gSavedSettings, "AudioStreamingMusic", true); + if (streaming_music) { + static LLCachedControl autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1); + static LLCachedControl tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true); // only play music when you enter a new parcel if the UI control for this // was not *explicitly* stopped by the user. (part of SL-4878) LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); - if ((nearby_media_panel && - nearby_media_panel->getParcelAudioAutoStart()) || - // or they have expressed no opinion in the UI, but have autoplay on... - (!nearby_media_panel && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) + + // ask mode //todo constants + if (autoplay_mode == 2) + { + // stop previous stream + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + + // if user set media to play - ask + if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) + || (!nearby_media_panel && tentative_autoplay)) + { + LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, + local_id, + music_url, + onStartMusicResponse); + } + else + { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); + } + } + // autoplay + else if ((nearby_media_panel + && nearby_media_panel->getParcelAudioAutoStart()) + // or they have expressed no opinion in the UI, but have autoplay on... + || (!nearby_media_panel + && autoplay_mode == 1 + && tentative_autoplay)) { LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 8d16cb815e..14b7cca7d5 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -272,7 +272,8 @@ public: // *NOTE: Taken out 2005-03-21. Phoenix. //void makeLandmarkAtSelection(); - static void optionally_start_music(const std::string& music_url); + static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id); static void processParcelOverlay(LLMessageSystem *msg, void **user_data); static void processParcelProperties(LLMessageSystem *msg, void **user_data); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 15b2ac8acf..85d87a43af 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -359,16 +359,19 @@ void update_statistics() record(LLStatViewer::REBUILD_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Sort Draw State"))); record(LLStatViewer::RENDER_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Render Geometry"))); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); - if (cdp) + if (gAgent.getRegion() && isAgentAvatarValid()) { - sample(LLStatViewer::SIM_PING, F64Milliseconds (cdp->getPingDelay())); - gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); - gSimPingCount++; - } - else - { - sample(LLStatViewer::SIM_PING, U32Seconds(10)); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); + if (cdp) + { + sample(LLStatViewer::SIM_PING, F64Milliseconds(cdp->getPingDelay())); + gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); + gSimPingCount++; + } + else + { + sample(LLStatViewer::SIM_PING, U32Seconds(10)); + } } if (LLViewerStats::instance().getRecording().getSum(LLStatViewer::FPS)) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index c22170e387..adc56a8622 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1591,6 +1591,11 @@ void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) handleScrollWheel( clicks ); } +void LLViewerWindow::handleScrollHWheel(LLWindow *window, S32 clicks) +{ + handleScrollHWheel(clicks); +} + void LLViewerWindow::handleWindowBlock(LLWindow *window) { send_agent_pause(); @@ -3006,6 +3011,49 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) return; } +void LLViewerWindow::handleScrollHWheel(S32 clicks) +{ + LLUI::getInstance()->resetMouseIdleTimer(); + + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if (mouse_captor) + { + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + mouse_captor->handleScrollHWheel(local_x, local_y, clicks); + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel handled by captor " << mouse_captor->getName() << LL_ENDL; + } + return; + } + + LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + if (top_ctrl) + { + S32 local_x; + S32 local_y; + top_ctrl->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + if (top_ctrl->handleScrollHWheel(local_x, local_y, clicks)) return; + } + + if (mRootView->handleScrollHWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks)) + { + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel" << LLView::sMouseHandlerMessage << LL_ENDL; + } + return; + } + else if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel not handled by view" << LL_ENDL; + } + + return; +} + void LLViewerWindow::addPopup(LLView* popup) { if (mPopupView) @@ -4697,7 +4745,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) && (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui) { - if (scratch_space.allocate(image_width, image_height, GL_DEPTH_COMPONENT, true, true)) + U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; + if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) { original_width = gPipeline.mDeferredScreen.getWidth(); original_height = gPipeline.mDeferredScreen.getHeight(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index d084642fdc..385bbd57e5 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -208,6 +208,7 @@ public: /*virtual*/ void handleMenuSelect(LLWindow *window, S32 menu_item); /*virtual*/ BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); /*virtual*/ void handleScrollWheel(LLWindow *window, S32 clicks); + /*virtual*/ void handleScrollHWheel(LLWindow *window, S32 clicks); /*virtual*/ BOOL handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleWindowBlock(LLWindow *window); /*virtual*/ void handleWindowUnblock(LLWindow *window); @@ -326,6 +327,7 @@ public: BOOL handleKey(KEY key, MASK mask); BOOL handleKeyUp(KEY key, MASK mask); void handleScrollWheel (S32 clicks); + void handleScrollHWheel (S32 clicks); // add and remove views from "popup" layer void addPopup(LLView* popup); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 195e78f775..83b27064de 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2050,8 +2050,10 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) LL_ERRS() << "Error resetting skeleton" << LL_ENDL; } - // Reset attachment points (buildSkeleton only does bones and CVs) - bool ignore_hud_joints = true; + // Reset attachment points + // BuildSkeleton only does bones and CVs but we still need to reinit huds + // since huds can be animated. + bool ignore_hud_joints = !isSelf(); initAttachmentPoints(ignore_hud_joints); // Fix up collision volumes @@ -6659,7 +6661,7 @@ void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) { - //don't process hud joint for other avatars, or when doing a skeleton reset. + //don't process hud joint for other avatars. continue; } @@ -10450,7 +10452,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() // Diagnostic list of all textures on our avatar static std::set all_textures; - if (mVisualComplexityStale) + if (mVisualComplexityStale) { U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 8a03edb5f5..0754e31c91 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1169,7 +1169,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, { const F32 HEIGHT_THRESHOLD = 7.f; LLUIImagePtr dot_image = sAvatarLevelImage; - if (unknown_relative_z) + if (unknown_relative_z && llabs(relative_z) > HEIGHT_THRESHOLD) { dot_image = sAvatarUnknownImage; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c91acc3758..cbf477d76f 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1006,7 +1006,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mDeferredLight.release(); } - F32 scale = RenderShadowResolutionScale; + F32 scale = llmax(0.f, RenderShadowResolutionScale); if (shadow_detail > 0) { //allocate 4 sun shadow maps @@ -8728,10 +8728,24 @@ void LLPipeline::renderDeferredLighting() } const LLViewerObject *vobj = drawablep->getVObj(); - if(vobj && vobj->getAvatar() - && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList())) + if (vobj) { - continue; + LLVOAvatar *av = vobj->getAvatar(); + if (av) + { + if (av->isTooComplex() || av->isInMuteList() || dist_vec(av->getPosition(), LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip) + { + continue; + } + } + else + { + const LLViewerObject *root_obj = drawablep->getParent() ? drawablep->getParent()->getVObj() : vobj; + if (root_obj && dist_vec(root_obj->getPosition(), LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip) + { + continue; + } + } } LLVector4a center; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 7482ec994c..17340e0858 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -143,7 +143,6 @@ with the same filename but different name - diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml index 4dd64cba2a..8f55b3297f 100644 --- a/indra/newview/skins/default/xui/de/floater_about_land.xml +++ b/indra/newview/skins/default/xui/de/floater_about_land.xml @@ -30,7 +30,7 @@ Immer - + Nur neue Benutzer diff --git a/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml deleted file mode 100644 index 4070dee84c..0000000000 --- a/indra/newview/skins/default/xui/de/floater_merchant_outbox.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - 1 Ordner - - - [NUM] Ordner - - - Ordner übertragen... - - - Initialisieren... - - - - - - Laden... - - - - - - - Artikel hierher ziehen, um Ordner zu erstellen - - - + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 9e7023d2f2..ece6c95080 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -99,6 +99,7 @@ label="Bubble Chat" layout="topleft" top_pad="4" + left_delta="0" name="bubble_text_chat" width="330"> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 649403184d..c2defdd772 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -322,17 +322,40 @@ name="enable_voice_check" width="110"/> - + + Media auto-play + + + + + + Buying this costs L$ [AMOUNT] Unknown file extension .%s -Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh +Expected .wav, .tga, .bmp, .jpg, .jpeg, or .anim Block Block @@ -4085,7 +4085,6 @@ Try enclosing path to the editor with double quotes. Marketplace Mini-map Walk / run / fly - Merchant outbox People Picks Places @@ -4115,7 +4114,6 @@ Try enclosing path to the editor with double quotes. Sell your creation Show nearby people Moving your avatar - Transfer items to your marketplace for sale Friends, groups, and nearby people Places to show as favorites in your profile Places you've saved diff --git a/indra/newview/skins/default/xui/es/floater_about_land.xml b/indra/newview/skins/default/xui/es/floater_about_land.xml index 998d2a8863..57a1b2ec1e 100644 --- a/indra/newview/skins/default/xui/es/floater_about_land.xml +++ b/indra/newview/skins/default/xui/es/floater_about_land.xml @@ -362,7 +362,7 @@ Sólo las parcelas más grandes pueden listarse en la búsqueda. Foto: - + Los avatares de otras parcelas pueden ver a los avatares de esta parcela y chatear con ellos @@ -444,7 +444,7 @@ los media: Una o más de esta opciones está configurada a nivel del estado - + diff --git a/indra/newview/skins/default/xui/es/floater_buy_currency.xml b/indra/newview/skins/default/xui/es/floater_buy_currency.xml index 2c8848265f..dbff3fcf0e 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_currency.xml @@ -60,7 +60,7 @@ no el objeto.