diff options
author | Oz Linden <oz@lindenlab.com> | 2016-05-06 09:05:51 -0400 |
---|---|---|
committer | Oz Linden <oz@lindenlab.com> | 2016-05-06 09:05:51 -0400 |
commit | a07a8cbf6eca73272f2c774df7122a1f0c5e1aa9 (patch) | |
tree | f716bdae5a265aabf8f9da1413df6a19fe3ada52 /indra | |
parent | c938e165062cbe53065dcdaa434fc1c3d9f38774 (diff) | |
parent | 94559950a2c670990db56bd74e65d26652421b8c (diff) |
merge changes for 4.0.4-release
Diffstat (limited to 'indra')
102 files changed, 1201 insertions, 509 deletions
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 578a2b62c8..2d5f964deb 100755 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -229,6 +229,28 @@ LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requ return value; } +LLSD llcoro::suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, + F32 timeoutin, const LLSD &timeoutResult) +{ + /** + * The timeout pump is attached upstream of of the waiting pump and will + * pass the timeout event through it. We CAN NOT attach downstream since + * doing so will cause the suspendPump to fire any waiting events immediately + * and they will be lost. This becomes especially problematic with the + * LLEventTimeout(pump) constructor which will also attempt to fire those + * events using the virtual listen_impl method in the not yet fully constructed + * timeoutPump. + */ + LLEventTimeout timeoutPump; + LLEventPump &suspendPump = suspendPumpOrName.getPump(); + + LLTempBoundListener timeoutListener(timeoutPump.listen(suspendPump.getName(), + boost::bind(&LLEventPump::post, &suspendPump, _1))); + + timeoutPump.eventAfter(timeoutin, timeoutResult); + return llcoro::suspendUntilEventOn(suspendPump); +} + namespace { diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 2105faf861..87926c692d 100755 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -147,6 +147,11 @@ LLSD suspendUntilEventOn(const LLEventPumpOrPumpName& pump) return postAndSuspend(LLSD(), LLEventPumpOrPumpName(), pump); } +/// Suspend the coroutine until an event is fired on the identified pump +/// or the timeout duration has elapsed. If the timeout duration +/// elapses the specified LLSD is returned. +LLSD suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, F32 timeoutin, const LLSD &timeoutResult); + } // namespace llcoro /// return type for two-pump variant of suspendUntilEventOn() diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index d36a107254..64ab58adcd 100755 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -39,9 +39,9 @@ #include "llsdutil.h" // llsd_matches() LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak): - LLEventStream(name, tweak) + LLEventStream(name, tweak), + mSource(source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1))) { - source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1)); } LLEventMatching::LLEventMatching(const LLSD& pattern): diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index e822a664f5..66f3c14869 100755 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -49,6 +49,9 @@ public: /// Post an event to all listeners virtual bool post(const LLSD& event) = 0; + +private: + LLTempBoundListener mSource; }; /** @@ -181,11 +184,23 @@ protected: private: bool tick(const LLSD&); - LLBoundListener mMainloop; + LLTempBoundListener mMainloop; Action mAction; }; -/// Production implementation of LLEventTimoutBase +/** + * Production implementation of LLEventTimoutBase. + * + * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) + * constructor to ensure that the upstream event pump is not an LLEventMaildrop + * or any other kind of store and forward pump which may have events outstanding. + * Using this constructor will cause the upstream event pump to fire any pending + * events and could result in the invocation of a virtual method before the timeout + * has been fully constructed. The timeout should instead be connected upstream + * from the event pump and attached using the listen method. + * See llcoro::suspendUntilEventOnWithTimeout() for an example. + */ + class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase { public: diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 6175329a9d..ba4fcd766e 100755 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -616,6 +616,12 @@ public: * a queue. Subsequent attaching listeners will receive stored events from the queue * until a listener indicates that the event has been handled. In order to receive * multiple events from a mail drop the listener must disconnect and reconnect. + * + * @NOTE: When using an LLEventMailDrop (or LLEventQueue) with a LLEventTimeout or + * LLEventFilter attaching the filter downstream using Timeout's constructor will + * cause the MailDrop to discharge any of it's stored events. The timeout should + * instead be connected upstream using its listen() method. + * See llcoro::suspendUntilEventOnWithTimeout() for an example. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index c51e0e0ae6..58f02d4d2b 100755 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -118,8 +118,10 @@ public: if (end_y < mBottom) clip_y = end_y - mBottom; // clip_? and delta_? should have same sign, since starting point is in rect // so ratios will be positive - F32 ratio_x = ((F32)clip_x / (F32)delta_x); - F32 ratio_y = ((F32)clip_y / (F32)delta_y); + F32 ratio_x = 0; + F32 ratio_y = 0; + if (delta_x != 0) ratio_x = ((F32)clip_x / (F32)delta_x); + if (delta_y != 0) ratio_y = ((F32)clip_y / (F32)delta_y); if (ratio_x > ratio_y) { // clip along x direction diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index f0fe1ab01b..d4c0788b7d 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -36,7 +36,8 @@ static std::map<std::string, U32> DefaultPoolSizes = boost::assign::map_list_of (std::string("Upload"), 1) - (std::string("AIS"), 25); + (std::string("AIS"), 1); + // *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync. #define DEFAULT_POOL_SIZE 5 diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 9a23ede81b..7742cbc182 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -41,14 +41,41 @@ #include "message.h" // for getting the port -using namespace LLCore; +using namespace LLCore; namespace LLCoreHttpUtil { const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; +namespace +{ + const std::string HTTP_LOGBODY_KEY("HTTPLogBodyOnError"); + + BoolSettingQuery_t mBoolSettingGet; + BoolSettingUpdate_t mBoolSettingPut; + + inline bool getBoolSetting(const std::string &keyname) + { + if (!mBoolSettingGet || mBoolSettingGet.empty()) + return(false); + return mBoolSettingGet(HTTP_LOGBODY_KEY); + } + +} + +void setPropertyMethods(BoolSettingQuery_t queryfn, BoolSettingUpdate_t updatefn) +{ + mBoolSettingGet = queryfn; + mBoolSettingPut = updatefn; + + if (mBoolSettingPut && !mBoolSettingPut.empty()) + { + mBoolSettingPut(HTTP_LOGBODY_KEY, false, "Log the entire HTTP body in the case of an HTTP error."); + } +} + void logMessageSuccess(std::string logAuth, std::string url, std::string message) { @@ -293,10 +320,11 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons bas >> std::noskipws; bodyData.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); httpStatus["error_body"] = LLSD(bodyData); -#if 1 - // commenting out, but keeping since this can be useful for debugging - LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; -#endif + if (getBoolSetting(HTTP_LOGBODY_KEY)) + { + // commenting out, but keeping since this can be useful for debugging + LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; + } } mReplyPump.post(result); diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index d21f5ff45c..6f0b865f83 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -57,7 +57,14 @@ /// namespace LLCoreHttpUtil { - extern const F32 HTTP_REQUEST_EXPIRY_SECS; +/// Allow access to to the property settings methods. +typedef boost::function<bool(const std::string &)> BoolSettingQuery_t; +typedef boost::function<void(const std::string &, bool, const std::string &)> BoolSettingUpdate_t; + +void setPropertyMethods(BoolSettingQuery_t queryfn, BoolSettingUpdate_t updatefn); + + +extern const F32 HTTP_REQUEST_EXPIRY_SECS; /// Attempt to convert a response object's contents to LLSD. /// It is expected that the response body will be of non-zero diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 52b8de8365..b30bc1aed6 100755 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -345,15 +345,11 @@ void LLGLSLShader::unloadInternal() GLhandleARB obj[1024]; GLsizei count; - glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj); + glGetAttachedObjectsARB(mProgramObject, sizeof(obj)/sizeof(obj[0]), &count, obj); for (GLsizei i = 0; i < count; i++) { -#if !LL_DARWIN - if (glIsProgramARB(obj[i])) -#endif - { - glDeleteObjectARB(obj[i]); - } + glDetachObjectARB(mProgramObject, obj[i]); + glDeleteObjectARB(obj[i]); } glDeleteObjectARB(mProgramObject); diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 56e263c5f1..3a6eebebba 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -112,7 +112,8 @@ void LLGLTexture::setBoostLevel(S32 level) if(mBoostLevel != level) { mBoostLevel = level ; - if(mBoostLevel != LLGLTexture::BOOST_NONE) + if(mBoostLevel != LLGLTexture::BOOST_NONE + && mBoostLevel != LLGLTexture::BOOST_ICON) { setNoDelete() ; } diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index f841901801..82b01e705d 100755 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -83,7 +83,12 @@ void LLIconCtrl::draw() // virtual // value might be a string or a UUID -void LLIconCtrl::setValue(const LLSD& value ) +void LLIconCtrl::setValue(const LLSD& value) +{ + setValue(value, mPriority); +} + +void LLIconCtrl::setValue(const LLSD& value, S32 priority) { LLSD tvalue(value); if (value.isString() && LLUUID::validate(value.asString())) @@ -94,11 +99,11 @@ void LLIconCtrl::setValue(const LLSD& value ) LLUICtrl::setValue(tvalue); if (tvalue.isUUID()) { - mImagep = LLUI::getUIImageByID(tvalue.asUUID(), mPriority); + mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority); } else { - mImagep = LLUI::getUIImage(tvalue.asString(), mPriority); + mImagep = LLUI::getUIImage(tvalue.asString(), priority); } if(mImagep.notNull() diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 7971cd44d3..dd83e78fd3 100755 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -59,6 +59,8 @@ protected: LLIconCtrl(const Params&); friend class LLUICtrlFactory; + void setValue(const LLSD& value, S32 priority); + public: virtual ~LLIconCtrl(); diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 77e7d375c8..0cb959a315 100755 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -417,6 +417,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mExpireOption(p.expire_option), mURLOption(p.url.option), mURLTarget(p.url.target), + mForceUrlsExternal(p.force_urls_external), mUnique(p.unique.isProvided()), mCombineBehavior(p.unique.combine), mPriority(p.priority), @@ -748,6 +749,11 @@ S32 LLNotification::getURLOpenExternally() const return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); } +bool LLNotification::getForceUrlsExternal() const +{ + return (mTemplatep ? mTemplatep->mForceUrlsExternal : false); +} + bool LLNotification::hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 010e6caba2..354add0b82 100755 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -553,7 +553,8 @@ public: std::string getLabel() const; std::string getURL() const; S32 getURLOption() const; - S32 getURLOpenExternally() const; + S32 getURLOpenExternally() const; //for url responce option + bool getForceUrlsExternal() const; bool canLogToChat() const; bool canLogToIM() const; bool canShowToast() const; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index c23fc53763..bed29254d8 100755 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -177,7 +177,8 @@ struct LLNotificationTemplate Optional<bool> persist, log_to_im, show_toast, - log_to_chat; + log_to_chat, + force_urls_external; Optional<std::string> functor, icon, label, @@ -201,6 +202,7 @@ struct LLNotificationTemplate log_to_im("log_to_im", false), show_toast("show_toast", true), log_to_chat("log_to_chat", true), + force_urls_external("force_urls_external", false), functor("functor"), icon("icon"), label("label"), @@ -284,11 +286,16 @@ struct LLNotificationTemplate // that URL. Obsolete this and eliminate the buttons for affected // messages when we allow clickable URLs in the UI U32 mURLOption; - - std::string mURLTarget; - //This is a flag that tells if the url needs to open externally dispite + + //This is a flag that tells if option url needs to open externally dispite //what the user setting is. - + std::string mURLTarget; + + // All links clicked inside notification will be opened in external browser + // Note: Some notifications block and exit viewer, yet they provide a link + // to click, we should be able to open such links in external browser. + bool mForceUrlsExternal; + // does this notification persist across sessions? if so, it will be // serialized to disk on first receipt and read on startup bool mPersist; diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index b53bb16d97..8cf72928ff 100755 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -179,6 +179,18 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) return FALSE; } + if (index < -1) + { + // less then minimum value + return FALSE; + } + + if (index < 0 && mSelectedIndex >= 0 && !mAllowDeselect) + { + // -1 is "nothing selected" + return FALSE; + } + if (mSelectedIndex >= 0) { LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex]; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 4309e6557e..4ccf1ef009 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -164,6 +164,7 @@ LLTextBase::Params::Params() trusted_content("trusted_content", true), use_ellipses("use_ellipses", false), parse_urls("parse_urls", false), + force_urls_external("force_urls_external", false), parse_highlights("parse_highlights", false) { addSynonym(track_end, "track_bottom"); @@ -216,6 +217,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mWordWrap(p.wrap), mUseEllipses( p.use_ellipses ), mParseHTML(p.parse_urls), + mForceUrlsExternal(p.force_urls_external), mParseHighlights(p.parse_highlights), mBGVisible(p.bg_visible), mScroller(NULL), @@ -1937,7 +1939,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url)); registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url)); registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); - registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); + registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url, true)); registrar.add("Url.Block", boost::bind(&LLUrlAction::blockObject, url)); registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); @@ -3227,7 +3229,15 @@ BOOL LLNormalTextSegment::handleMouseUp(S32 x, S32 y, MASK mask) // Only process the click if it's actually in this segment, not to the right of the end-of-line. if(mEditor.getSegmentAtLocalPos(x, y, false) == this) { - LLUrlAction::clickAction(getStyle()->getLinkHREF(), mEditor.isContentTrusted()); + std::string url = getStyle()->getLinkHREF(); + if (!mEditor.mForceUrlsExternal) + { + LLUrlAction::clickAction(url, mEditor.isContentTrusted()); + } + else if (!LLUrlAction::executeSLURL(url, mEditor.isContentTrusted())) + { + LLUrlAction::openURLExternal(url); + } return TRUE; } } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index ac408bbe7a..7d87271b0e 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -300,6 +300,7 @@ public: wrap, use_ellipses, parse_urls, + force_urls_external, parse_highlights, clip, clip_partial, @@ -654,6 +655,7 @@ protected: S32 mLineSpacingPixels; // padding between lines bool mBorderVisible; bool mParseHTML; // make URLs interactive + bool mForceUrlsExternal; // URLs from this textbox will be opened in external browser bool mParseHighlights; // highlight user-defined keywords bool mWordWrap; bool mUseEllipses; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 926326aaff..3c86b539c4 100755 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1716,7 +1716,20 @@ void LLTextEditor::unindentLineBeforeCloseBrace() LLWString text = getWText(); if( ' ' == text[ mCursorPos - 1 ] ) { - removeCharOrTab(); + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } } } } @@ -1800,7 +1813,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) // Handle most keys only if the text editor is writeable. if( !mReadOnly ) { - if( '}' == uni_char ) + if( mAutoIndent && '}' == uni_char ) { unindentLineBeforeCloseBrace(); } diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 12537d9dd1..027a3e3a64 100755 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -83,12 +83,13 @@ void LLUrlAction::openURLExternal(std::string url) } } -void LLUrlAction::executeSLURL(std::string url) +bool LLUrlAction::executeSLURL(std::string url, bool trusted_content) { if (sExecuteSLURLCallback) { - sExecuteSLURLCallback(url ,true); + return sExecuteSLURLCallback(url, trusted_content); } + return false; } void LLUrlAction::clickAction(std::string url, bool trusted_content) diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index 5f3626490c..5497e28bb4 100755 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -57,7 +57,7 @@ public: static void openURLExternal(std::string url); /// execute the given secondlife: SLURL - static void executeSLURL(std::string url); + static bool executeSLURL(std::string url, bool trusted_content = true); /// if the Url specifies an SL location, teleport there static void teleportToLocation(std::string url); diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 406bc9cf47..22f3339cf1 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -25,13 +25,69 @@ */ #import "llopenglview-objc.h" -#include "llwindowmacosx-objc.h" +#import "llwindowmacosx-objc.h" #import "llappdelegate-objc.h" +#pragma mark local functions +NativeKeyEventData extractKeyDataFromKeyEvent(NSEvent* theEvent) +{ + NativeKeyEventData eventData; + eventData.mKeyEvent = NativeKeyEventData::KEYUNKNOWN; + eventData.mEventType = [theEvent type]; + eventData.mEventModifiers = [theEvent modifierFlags]; + eventData.mEventKeyCode = [theEvent keyCode]; + NSString *strEventChars = [theEvent characters]; + eventData.mEventChars = (strEventChars.length) ? [strEventChars characterAtIndex:0] : 0; + NSString *strEventUChars = [theEvent charactersIgnoringModifiers]; + eventData.mEventUnmodChars = (strEventUChars.length) ? [strEventUChars characterAtIndex:0] : 0; + eventData.mEventRepeat = [theEvent isARepeat]; + return eventData; +} + +NativeKeyEventData extractKeyDataFromModifierEvent(NSEvent* theEvent) +{ + NativeKeyEventData eventData; + eventData.mKeyEvent = NativeKeyEventData::KEYUNKNOWN; + eventData.mEventType = [theEvent type]; + eventData.mEventModifiers = [theEvent modifierFlags]; + eventData.mEventKeyCode = [theEvent keyCode]; + return eventData; +} +attributedStringInfo getSegments(NSAttributedString *str) +{ + attributedStringInfo segments; + segment_lengths seg_lengths; + segment_standouts seg_standouts; + NSRange effectiveRange; + NSRange limitRange = NSMakeRange(0, [str length]); + + while (limitRange.length > 0) { + NSNumber *attr = [str attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange]; + limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); + + if (effectiveRange.length <= 0) + { + effectiveRange.length = 1; + } + + if ([attr integerValue] == 2) + { + seg_lengths.push_back(effectiveRange.length); + seg_standouts.push_back(true); + } else + { + seg_lengths.push_back(effectiveRange.length); + seg_standouts.push_back(false); + } + } + segments.seg_lengths = seg_lengths; + segments.seg_standouts = seg_standouts; + return segments; +} -//--------------------------- +#pragma mark class implementations @implementation NSScreen (PointConversion) @@ -63,53 +119,6 @@ @end -void extractKeyDataFromEvent (NSEvent *theEvent, NativeKeyEventData * eventData) -{ - eventData->mKeyEvent = NativeKeyEventData::KEYUNKNOWN; - eventData->mEventType = [theEvent type]; - eventData->mEventModifiers = [theEvent modifierFlags]; - eventData->mEventKeyCode = [theEvent keyCode]; - NSString *strEventChars = [theEvent characters]; - eventData->mEventChars = (strEventChars.length) ? [strEventChars characterAtIndex:0] : 0; - NSString *strEventUChars = [theEvent charactersIgnoringModifiers]; - eventData->mEventUnmodChars = (strEventUChars.length) ? [strEventUChars characterAtIndex:0] : 0; - eventData->mEventRepeat = [theEvent isARepeat]; - -} - - -attributedStringInfo getSegments(NSAttributedString *str) -{ - attributedStringInfo segments; - segment_lengths seg_lengths; - segment_standouts seg_standouts; - NSRange effectiveRange; - NSRange limitRange = NSMakeRange(0, [str length]); - - while (limitRange.length > 0) { - NSNumber *attr = [str attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange]; - limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); - - if (effectiveRange.length <= 0) - { - effectiveRange.length = 1; - } - - if ([attr integerValue] == 2) - { - seg_lengths.push_back(effectiveRange.length); - seg_standouts.push_back(true); - } else - { - seg_lengths.push_back(effectiveRange.length); - seg_standouts.push_back(false); - } - } - segments.seg_lengths = seg_lengths; - segments.seg_standouts = seg_standouts; - return segments; -} - @implementation LLOpenGLView // Force a high quality update after live resizing @@ -341,6 +350,9 @@ attributedStringInfo getSegments(NSAttributedString *str) callRightMouseUp(mMousePos, [theEvent modifierFlags]); mSimulatedRightClick = false; } else { + NSPoint mPoint = [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; callLeftMouseUp(mMousePos, [theEvent modifierFlags]); } } @@ -388,7 +400,7 @@ attributedStringInfo getSegments(NSAttributedString *str) NSPoint mPoint = [theEvent locationInWindow]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; - callMouseMoved(mMousePos, 0); + callMouseDragged(mMousePos, 0); } - (void) otherMouseDown:(NSEvent *)theEvent @@ -423,18 +435,14 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) keyUp:(NSEvent *)theEvent { - NativeKeyEventData eventData; - - extractKeyDataFromEvent( theEvent, &eventData ); + NativeKeyEventData eventData = extractKeyDataFromKeyEvent(theEvent); eventData.mKeyEvent = NativeKeyEventData::KEYUP; callKeyUp(&eventData, [theEvent keyCode], [theEvent modifierFlags]); } - (void) keyDown:(NSEvent *)theEvent { - NativeKeyEventData eventData; - - extractKeyDataFromEvent( theEvent, &eventData ); + NativeKeyEventData eventData = extractKeyDataFromKeyEvent(theEvent); eventData.mKeyEvent = NativeKeyEventData::KEYDOWN; uint keycode = [theEvent keyCode]; @@ -472,9 +480,7 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void)flagsChanged:(NSEvent *)theEvent { - NativeKeyEventData eventData; - - extractKeyDataFromEvent( theEvent, &eventData ); + NativeKeyEventData eventData = extractKeyDataFromModifierEvent(theEvent); mModifiers = [theEvent modifierFlags]; callModifier([theEvent modifierFlags]); diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index eadff8a6b4..d2afb3f91b 100755 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -112,6 +112,10 @@ void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, M { } +void LLWindowCallbacks::handleMouseDragged(LLWindow *window, const LLCoordGL pos, MASK mask) +{ +} + void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) { } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 7da5959700..6a7137e593 100755 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -52,6 +52,7 @@ public: virtual BOOL handleActivate(LLWindow *window, BOOL activated); virtual BOOL handleActivateApp(LLWindow *window, BOOL activating); 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 handleResize(LLWindow *window, S32 width, S32 height); virtual void handleFocus(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index dc184b91fb..c22f3382fb 100755 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -55,13 +55,13 @@ struct NativeKeyEventData { KEYCHAR }; - EventType mKeyEvent; - uint32_t mEventType; - uint32_t mEventModifiers; - uint32_t mEventKeyCode; - uint32_t mEventChars; - uint32_t mEventUnmodChars; - bool mEventRepeat; + EventType mKeyEvent = KEYUNKNOWN; + uint32_t mEventType = 0; + uint32_t mEventModifiers = 0; + uint32_t mEventKeyCode = 0; + uint32_t mEventChars = 0; + uint32_t mEventUnmodChars = 0; + bool mEventRepeat = false; }; typedef const NativeKeyEventData * NSKeyEventRef; @@ -92,6 +92,7 @@ void setCrossCursor(); void setNotAllowedCursor(); void hideNSCursor(); void showNSCursor(); +bool isCGCursorVisible(); void hideNSCursorTillMove(bool hide); void requestUserAttention(); long showAlert(std::string title, std::string text, int type); @@ -133,6 +134,7 @@ void callLeftMouseUp(float *pos, unsigned int mask); 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 callMouseExit(); void callWindowFocus(); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 1a21bf8430..43ce9a2255 100755 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -163,6 +163,11 @@ void showNSCursor() [NSCursor unhide]; } +bool isCGCursorVisible() +{ + return CGCursorIsVisible(); +} + void hideNSCursorTillMove(bool hide) { [NSCursor setHiddenUntilMouseMoves:hide]; diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 0d41884462..754306b5d2 100755 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -343,6 +343,18 @@ void callMouseMoved(float *pos, MASK mask) //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); } +void callMouseDragged(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} + void callScrollMoved(float delta) { gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta); @@ -1445,8 +1457,15 @@ void LLWindowMacOSX::updateCursor() mNextCursor = UI_CURSOR_WORKING; } - if(mCurrentCursor == mNextCursor) - return; + if(mCurrentCursor == mNextCursor) + { + if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) + { + hideNSCursor(); + adjustCursorDecouple(); + } + return; + } // RN: replace multi-drag cursors with single versions if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index c5106e6d13..7636e75650 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -4.0.4 +4.0.5 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c4a8fe3532..15f6fe5649 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4856,6 +4856,17 @@ <key>Value</key> <integer>7</integer> </map> + <key>InventoryTrashMaxCapacity</key> + <map> + <key>Comment</key> + <string>Maximum capacity of the Trash folder. User will ve offered to clean it up when exceeded.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>5000</integer> + </map> <key>MarketplaceListingsSortOrder</key> <map> <key>Comment</key> @@ -7004,6 +7015,28 @@ <key>Value</key> <integer>1</integer> </map> + <key>NotifyMoneySpend</key> + <map> + <key>Comment</key> + <string>Pop up notifications when spending L$</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>NotifyMoneyReceived</key> + <map> + <key>Comment</key> + <string>Pop up notifications when receiving L$</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>NotifyTipDuration</key> <map> <key>Comment</key> @@ -8171,6 +8204,17 @@ <key>Value</key> <integer>256</integer> </map> + <key>RegionCheckTextureHeights</key> + <map> + <key>Comment</key> + <string>Don't allow user to set low heights greater than high</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RememberPassword</key> <map> <key>Comment</key> @@ -14446,7 +14490,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>25</integer> + <integer>1</integer> </map> <key>PoolSizeUpload</key> <map> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index c62b45ed81..fd6b1b5b3f 100755 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -98,7 +98,18 @@ <string>Boolean</string> <key>Value</key> <integer>1</integer> - </map> + </map> + <key>NavigationBarRatio</key> + <map> + <key>Comment</key> + <string>The ratio between the width of Navigation layout panel and the width of whole Navigation layout stack</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.6</real> + </map> <key>InstantMessageLogPath</key> <map> <key>Comment</key> diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index 7dee309a62..49291ea564 100755 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -36,6 +36,8 @@ #include "llsecapi.h" #include <curl/curl.h> +#include "llcorehttputil.h" + // Here is where we begin to get our connection usage under control. // This establishes llcorehttp policy classes that, among other // things, limit the maximum number of connections to outside @@ -138,6 +140,9 @@ LLAppCoreHttp::~LLAppCoreHttp() void LLAppCoreHttp::init() { + LLCoreHttpUtil::setPropertyMethods( + boost::bind(&LLControlGroup::getBOOL, boost::ref(gSavedSettings), _1), + boost::bind(&LLControlGroup::declareBOOL, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_NONDFT)); LLCore::LLHttp::initialize(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 99dcb80a4a..cc676550ab 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -65,7 +65,12 @@ #pragma warning (disable:4702) #endif -#if 1 +namespace +{ + const S32 BAKE_RETRY_MAX_COUNT = 5; + const F32 BAKE_RETRY_TIMEOUT = 2.0F; +} + // *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. // temp code in transition void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id) @@ -73,8 +78,6 @@ void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id) if (cb.notNull()) cb->fire(id); } -#endif - std::string self_av_string() { @@ -2073,7 +2076,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) } const LLUUID& base_id = append ? getBaseOutfitUUID() : category; LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); - if (base_cat) + if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { LLSD base_contents; base_contents["name"] = base_cat->getName(); @@ -3354,12 +3357,36 @@ LLSD LLAppearanceMgr::dumpCOF() const void LLAppearanceMgr::requestServerAppearanceUpdate() { - LLCoprocedureManager::CoProcedure_t proc = boost::bind(&LLAppearanceMgr::serverAppearanceUpdateCoro, this, _1); - LLCoprocedureManager::instance().enqueueCoprocedure("AIS", "LLAppearanceMgr::serverAppearanceUpdateCoro", proc); + if (!mOutstandingAppearanceBakeRequest) + { +#ifdef APPEARANCEBAKE_AS_IN_AIS_QUEUE + mRerequestAppearanceBake = false; + LLCoprocedureManager::CoProcedure_t proc = boost::bind(&LLAppearanceMgr::serverAppearanceUpdateCoro, this, _1); + LLCoprocedureManager::instance().enqueueCoprocedure("AIS", "LLAppearanceMgr::serverAppearanceUpdateCoro", proc); +#else + LLCoros::instance().launch("serverAppearanceUpdateCoro", + boost::bind(&LLAppearanceMgr::serverAppearanceUpdateCoro, this)); + +#endif + } + else + { + mRerequestAppearanceBake = true; + } } +#ifdef APPEARANCEBAKE_AS_IN_AIS_QUEUE void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter) +#else +void LLAppearanceMgr::serverAppearanceUpdateCoro() +#endif { +#ifndef APPEARANCEBAKE_AS_IN_AIS_QUEUE + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( + new LLCoreHttpUtil::HttpCoroutineAdapter("serverAppearanceUpdateCoro", LLCore::HttpRequest::DEFAULT_POLICY_ID)); +#endif + + mRerequestAppearanceBake = false; if (!gAgent.getRegion()) { LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL; @@ -3386,57 +3413,57 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd return; } -#if 0 - static int reqcount = 0; - int r_count = ++reqcount; - LL_WARNS("Avatar") << "START: Server Bake request #" << r_count << "!" << LL_ENDL; -#endif - - // If we have already received an update for this or higher cof version, - // put a warning in the log but request anyway. - S32 cofVersion = getCOFVersion(); - S32 lastRcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; - S32 lastReq = gAgentAvatarp->mLastUpdateRequestCOFVersion; - - LL_INFOS("Avatar") << "Requesting COF version " << cofVersion << - " (Last Received:" << lastRcv << ")" << - " (Last Requested:" << lastReq << ")" << LL_ENDL; - - if ((cofVersion != LLViewerInventoryCategory::VERSION_UNKNOWN)) + llcoro::suspend(); + S32 retryCount(0); + bool bRetry; + do { - if (cofVersion < lastRcv) + BoolSetter outstanding(mOutstandingAppearanceBakeRequest); + + // If we have already received an update for this or higher cof version, + // put a warning in the log and cancel the request. + S32 cofVersion = getCOFVersion(); + S32 lastRcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; + S32 lastReq = gAgentAvatarp->mLastUpdateRequestCOFVersion; + + LL_INFOS("Avatar") << "Requesting COF version " << cofVersion << + " (Last Received:" << lastRcv << ")" << + " (Last Requested:" << lastReq << ")" << LL_ENDL; + + if (cofVersion == LLViewerInventoryCategory::VERSION_UNKNOWN) { - LL_WARNS("Avatar") << "Have already received update for cof version " << lastRcv - << " but requesting for " << cofVersion << LL_ENDL; + LL_WARNS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL; + return; } - if (lastReq > cofVersion) + else { - LL_WARNS("Avatar") << "Request already in flight for cof version " << lastReq - << " but requesting for " << cofVersion << LL_ENDL; + if (cofVersion < lastRcv) + { + LL_WARNS("Avatar") << "Have already received update for cof version " << lastRcv + << " but requesting for " << cofVersion << LL_ENDL; + return; + } + if (lastReq > cofVersion) + { + LL_WARNS("Avatar") << "Request already in flight for cof version " << lastReq + << " but requesting for " << cofVersion << LL_ENDL; + return; + } } - } - - // Actually send the request. - LL_DEBUGS("Avatar") << "Will send request for cof_version " << cofVersion << LL_ENDL; -// LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter( -// "UpdateAvatarAppearance", gAgent.getAgentPolicy())); + // Actually send the request. + LL_DEBUGS("Avatar") << "Will send request for cof_version " << cofVersion << LL_ENDL; - bool bRetry; - do - { bRetry = false; LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest()); - S32 reqCofVersion = getCOFVersion(); // Treat COF version (gets set by AISAPI as authoritative, - // not what the bake request tells us to use). if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) { - reqCofVersion += 999; + cofVersion += 999; LL_WARNS("Avatar") << "Forcing version failure on COF Baking" << LL_ENDL; } - LL_INFOS() << "Requesting bake for COF version " << reqCofVersion << LL_ENDL; + LL_INFOS() << "Requesting bake for COF version " << cofVersion << LL_ENDL; LLSD postData; if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) @@ -3445,10 +3472,10 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd } else { - postData["cof_version"] = reqCofVersion; + postData["cof_version"] = cofVersion; } - gAgentAvatarp->mLastUpdateRequestCOFVersion = reqCofVersion; + gAgentAvatarp->mLastUpdateRequestCOFVersion = cofVersion; LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); @@ -3466,14 +3493,30 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd // on multiple machines. if (result.has("expected")) { + S32 expectedCofVersion = result["expected"].asInteger(); + LL_WARNS("Avatar") << "Server expected " << expectedCofVersion << " as COF version" << LL_ENDL; + bRetry = true; // Wait for a 1/2 second before trying again. Just to keep from asking too quickly. - llcoro::suspendUntilTimeout(0.5); + if (++retryCount > BAKE_RETRY_MAX_COUNT) + { + LL_WARNS("Avatar") << "Bake retry count exceeded!" << LL_ENDL; + break; + } + F32 timeout = pow(BAKE_RETRY_TIMEOUT, static_cast<float>(retryCount)) - 1.0; - LL_WARNS("Avatar") << "Server expected " << expectedCofVersion << " as COF version" << LL_ENDL; + LL_WARNS("Avatar") << "Bake retry #" << retryCount << " in " << timeout << " seconds." << LL_ENDL; + + llcoro::suspendUntilTimeout(timeout); + bRetry = true; continue; } + else + { + LL_WARNS("Avatar") << "No retry attempted." << LL_ENDL; + break; + } } LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; @@ -3484,10 +3527,11 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd } while (bRetry); -#if 0 - LL_WARNS("Avatar") << "END: Server Bake request #" << r_count << "!" << LL_ENDL; -#endif - + if (mRerequestAppearanceBake) + { // A bake request came in while this one was still outstanding. + // Requeue ourself for a later request. + requestServerAppearanceUpdate(); + } } /*static*/ @@ -3855,7 +3899,9 @@ LLAppearanceMgr::LLAppearanceMgr(): mOutfitLocked(false), mInFlightCounter(0), mInFlightTimer(), - mIsInUpdateAppearanceFromCOF(false) + mIsInUpdateAppearanceFromCOF(false), + mOutstandingAppearanceBakeRequest(false), + mRerequestAppearanceBake(false) { LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); // unlock outfit on save operation completed diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b97f9018c0..bf181cb4ad 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -228,7 +228,12 @@ public: private: +#ifdef APPEARANCEBAKE_AS_IN_AIS_QUEUE void serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter); +#else + void serverAppearanceUpdateCoro(); +#endif + static void debugAppearanceUpdateCOF(const LLSD& content); std::string mAppearanceServiceURL; @@ -255,6 +260,8 @@ private: bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. + bool mOutstandingAppearanceBakeRequest; // A bake request is outstanding. Do not overlap. + bool mRerequestAppearanceBake; /** * Lock for blocking operations on outfit until server reply or timeout exceed diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 8dc8a2ff20..00bc8ebe87 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -564,7 +564,8 @@ namespace action_give_inventory static LLInventoryPanel* get_active_inventory_panel() { LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); - if (!active_panel) + LLFloater* floater_appearance = LLFloaterReg::findInstance("appearance"); + if (!active_panel || (floater_appearance && floater_appearance->hasFocus())) { active_panel = get_outfit_editor_inventory_panel(); } diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index 932326acae..c131dc641b 100755 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -196,7 +196,7 @@ LLAvatarIconCtrl::LLAvatarIconCtrl(const LLAvatarIconCtrl::Params& p) } else { - LLIconCtrl::setValue(mDefaultIconName); + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); } } @@ -243,7 +243,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value) // *TODO: Consider getting avatar icon/badge directly from // People API, rather than sending AvatarPropertyRequest // messages. People API already hits the user table. - LLIconCtrl::setValue(mDefaultIconName); + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); app->addObserver(mAvatarId, this); app->sendAvatarPropertiesRequest(mAvatarId); } @@ -284,7 +284,7 @@ bool LLAvatarIconCtrl::updateFromCache() } else { - LLIconCtrl::setValue(mDefaultIconName); + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); return false; } diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 4dbed114bb..f0331f20d8 100755 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -122,8 +122,6 @@ LLExpandableTextBox::LLTextBoxEx::LLTextBoxEx(const Params& p) void LLExpandableTextBox::LLTextBoxEx::reshape(S32 width, S32 height, BOOL called_from_parent) { LLTextEditor::reshape(width, height, called_from_parent); - - hideOrShowExpandTextAsNeeded(); } void LLExpandableTextBox::LLTextBoxEx::setText(const LLStringExplicit& text,const LLStyle::Params& input_params) @@ -298,6 +296,12 @@ void LLExpandableTextBox::updateTextBoxRect() mTextBox->reshape(rc.getWidth(), rc.getHeight()); mTextBox->setRect(rc); + // *HACK + // hideExpandText brakes text styles (replaces hyper-links with plain text), see ticket EXT-3290 + // Also text segments are not removed properly. Same issue at expandTextBox(). + // So set text again to make text box re-apply styles and clear segments. + // *TODO Find a solution that does not involve text segment. + mTextBox->setText(mText); } S32 LLExpandableTextBox::recalculateTextDelta(S32 text_delta) @@ -403,8 +407,6 @@ void LLExpandableTextBox::collapseTextBox() setRect(mCollapsedRect); updateTextBoxRect(); - - gViewerWindow->removePopup(this); } void LLExpandableTextBox::onFocusLost() @@ -423,13 +425,19 @@ void LLExpandableTextBox::onTopLost() void LLExpandableTextBox::updateTextShape() { - // I guess this should be done on every reshape(), - // but adding this code to reshape() currently triggers bug VWR-26455, - // which makes the text virtually unreadable. llassert(!mExpanded); updateTextBoxRect(); } +void LLExpandableTextBox::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + mExpanded = false; + LLUICtrl::reshape(width, height, called_from_parent); + updateTextBoxRect(); + + gViewerWindow->removePopup(this); +} + void LLExpandableTextBox::setValue(const LLSD& value) { collapseTextBox(); diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h index 90d46ab262..aaf393277f 100755 --- a/indra/newview/llexpandabletextbox.h +++ b/indra/newview/llexpandabletextbox.h @@ -147,6 +147,7 @@ public: * *HACK: Update the inner textbox shape. */ void updateTextShape(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); /** * Draws text box, collapses text box if its expanded and its parent's position changed diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index f9fd5069af..7f952d4dd4 100755 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -39,6 +39,7 @@ #include "llagent.h" #include "llagentaccess.h" +#include "llappviewer.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -475,13 +476,36 @@ BOOL LLPanelLandGeneral::postBuild() mBtnBuyLand = getChild<LLButton>("Buy Land..."); mBtnBuyLand->setClickedCallback(onClickBuyLand, (void*)&BUY_PERSONAL_LAND); + + mBtnBuyGroupLand = getChild<LLButton>("Buy For Group..."); + mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); + + + mBtnBuyPass = getChild<LLButton>("Buy Pass..."); + mBtnBuyPass->setClickedCallback(onClickBuyPass, this); + + mBtnReleaseLand = getChild<LLButton>("Abandon Land..."); + mBtnReleaseLand->setClickedCallback(onClickRelease, NULL); + + mBtnReclaimLand = getChild<LLButton>("Reclaim Land..."); + mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL); + + mBtnStartAuction = getChild<LLButton>("Linden Sale..."); + mBtnStartAuction->setClickedCallback(onClickStartAuction, this); + + mBtnScriptLimits = getChild<LLButton>("Scripts..."); + + if(gDisconnected) + { + return TRUE; + } + // note: on region change this will not be re checked, should not matter on Agni as // 99% of the time all regions will return the same caps. In case of an erroneous setting // to enabled the floater will just throw an error when trying to get it's cap std::string url = gAgent.getRegion()->getCapability("LandResources"); if (!url.empty()) { - mBtnScriptLimits = getChild<LLButton>("Scripts..."); if(mBtnScriptLimits) { mBtnScriptLimits->setClickedCallback(onClickScriptLimits, this); @@ -489,28 +513,11 @@ BOOL LLPanelLandGeneral::postBuild() } else { - mBtnScriptLimits = getChild<LLButton>("Scripts..."); if(mBtnScriptLimits) { mBtnScriptLimits->setVisible(false); } } - - mBtnBuyGroupLand = getChild<LLButton>("Buy For Group..."); - mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); - - - mBtnBuyPass = getChild<LLButton>("Buy Pass..."); - mBtnBuyPass->setClickedCallback(onClickBuyPass, this); - - mBtnReleaseLand = getChild<LLButton>("Abandon Land..."); - mBtnReleaseLand->setClickedCallback(onClickRelease, NULL); - - mBtnReclaimLand = getChild<LLButton>("Reclaim Land..."); - mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL); - - mBtnStartAuction = getChild<LLButton>("Linden Sale..."); - mBtnStartAuction->setClickedCallback(onClickStartAuction, this); return TRUE; } @@ -524,9 +531,58 @@ LLPanelLandGeneral::~LLPanelLandGeneral() // public void LLPanelLandGeneral::refresh() { - mBtnStartAuction->setVisible(gAgent.isGodlike()); + mEditName->setEnabled(FALSE); + mEditName->setText(LLStringUtil::null); - LLParcel *parcel = mParcel->getParcel(); + mEditDesc->setEnabled(FALSE); + mEditDesc->setText(getString("no_selection_text")); + + mTextSalePending->setText(LLStringUtil::null); + mTextSalePending->setEnabled(FALSE); + + mBtnDeedToGroup->setEnabled(FALSE); + mBtnSetGroup->setEnabled(FALSE); + mBtnStartAuction->setEnabled(FALSE); + + mCheckDeedToGroup ->set(FALSE); + mCheckDeedToGroup ->setEnabled(FALSE); + mCheckContributeWithDeed->set(FALSE); + mCheckContributeWithDeed->setEnabled(FALSE); + + mTextOwner->setText(LLStringUtil::null); + mContentRating->setText(LLStringUtil::null); + mLandType->setText(LLStringUtil::null); + mBtnProfile->setLabel(getString("profile_text")); + mBtnProfile->setEnabled(FALSE); + + mTextClaimDate->setText(LLStringUtil::null); + mTextGroup->setText(LLStringUtil::null); + mTextPrice->setText(LLStringUtil::null); + + mSaleInfoForSale1->setVisible(FALSE); + mSaleInfoForSale2->setVisible(FALSE); + mSaleInfoForSaleObjects->setVisible(FALSE); + mSaleInfoForSaleNoObjects->setVisible(FALSE); + mSaleInfoNotForSale->setVisible(FALSE); + mBtnSellLand->setVisible(FALSE); + mBtnStopSellLand->setVisible(FALSE); + + mTextPriceLabel->setText(LLStringUtil::null); + mTextDwell->setText(LLStringUtil::null); + + mBtnBuyLand->setEnabled(FALSE); + mBtnScriptLimits->setEnabled(FALSE); + mBtnBuyGroupLand->setEnabled(FALSE); + mBtnReleaseLand->setEnabled(FALSE); + mBtnReclaimLand->setEnabled(FALSE); + mBtnBuyPass->setEnabled(FALSE); + + if(gDisconnected) + { + return; + } + + mBtnStartAuction->setVisible(gAgent.isGodlike()); bool region_owner = false; LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if(regionp && (regionp->getOwner() == gAgent.getID())) @@ -540,56 +596,8 @@ void LLPanelLandGeneral::refresh() mBtnReleaseLand->setVisible(TRUE); mBtnReclaimLand->setVisible(FALSE); } - if (!parcel) - { - // nothing selected, disable panel - mEditName->setEnabled(FALSE); - mEditName->setText(LLStringUtil::null); - - mEditDesc->setEnabled(FALSE); - mEditDesc->setText(getString("no_selection_text")); - - mTextSalePending->setText(LLStringUtil::null); - mTextSalePending->setEnabled(FALSE); - - mBtnDeedToGroup->setEnabled(FALSE); - mBtnSetGroup->setEnabled(FALSE); - mBtnStartAuction->setEnabled(FALSE); - - mCheckDeedToGroup ->set(FALSE); - mCheckDeedToGroup ->setEnabled(FALSE); - mCheckContributeWithDeed->set(FALSE); - mCheckContributeWithDeed->setEnabled(FALSE); - - mTextOwner->setText(LLStringUtil::null); - mContentRating->setText(LLStringUtil::null); - mLandType->setText(LLStringUtil::null); - mBtnProfile->setLabel(getString("profile_text")); - mBtnProfile->setEnabled(FALSE); - - mTextClaimDate->setText(LLStringUtil::null); - mTextGroup->setText(LLStringUtil::null); - mTextPrice->setText(LLStringUtil::null); - - mSaleInfoForSale1->setVisible(FALSE); - mSaleInfoForSale2->setVisible(FALSE); - mSaleInfoForSaleObjects->setVisible(FALSE); - mSaleInfoForSaleNoObjects->setVisible(FALSE); - mSaleInfoNotForSale->setVisible(FALSE); - mBtnSellLand->setVisible(FALSE); - mBtnStopSellLand->setVisible(FALSE); - - mTextPriceLabel->setText(LLStringUtil::null); - mTextDwell->setText(LLStringUtil::null); - - mBtnBuyLand->setEnabled(FALSE); - mBtnScriptLimits->setEnabled(FALSE); - mBtnBuyGroupLand->setEnabled(FALSE); - mBtnReleaseLand->setEnabled(FALSE); - mBtnReclaimLand->setEnabled(FALSE); - mBtnBuyPass->setEnabled(FALSE); - } - else + LLParcel *parcel = mParcel->getParcel(); + if (parcel) { // something selected, hooray! BOOL is_leased = (LLParcel::OS_LEASED == parcel->getOwnershipStatus()); @@ -1246,7 +1254,7 @@ void LLPanelLandObjects::refresh() mOwnerList->deleteAllItems(); mOwnerList->setEnabled(FALSE); - if (!parcel) + if (!parcel || gDisconnected) { mSWTotalObjects->setTextArg("[COUNT]", llformat("%d", 0)); mSWTotalObjects->setTextArg("[TOTAL]", llformat("%d", 0)); @@ -1974,7 +1982,7 @@ void LLPanelLandOptions::refresh() refreshSearch(); LLParcel *parcel = mParcel->getParcel(); - if (!parcel) + if (!parcel || gDisconnected) { mCheckEditObjects ->set(FALSE); mCheckEditObjects ->setEnabled(FALSE); @@ -2154,7 +2162,7 @@ void LLPanelLandOptions::draw() void LLPanelLandOptions::refreshSearch() { LLParcel *parcel = mParcel->getParcel(); - if (!parcel) + if (!parcel || gDisconnected) { mCheckShowDirectory->set(FALSE); mCheckShowDirectory->setEnabled(FALSE); @@ -2419,7 +2427,7 @@ void LLPanelLandAccess::refresh() LLParcel *parcel = mParcel->getParcel(); // Display options - if (parcel) + if (parcel && !gDisconnected) { BOOL use_access_list = parcel->getParcelFlag(PF_USE_ACCESS_LIST); BOOL use_group = parcel->getParcelFlag(PF_USE_ACCESS_GROUP); @@ -2599,7 +2607,7 @@ void LLPanelLandAccess::refresh_ui() getChildView("remove_banned")->setEnabled(FALSE); LLParcel *parcel = mParcel->getParcel(); - if (parcel) + if (parcel && !gDisconnected) { BOOL can_manage_allowed = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_ALLOWED); BOOL can_manage_banned = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_BANNED); @@ -2945,7 +2953,7 @@ BOOL LLPanelLandCovenant::postBuild() void LLPanelLandCovenant::refresh() { LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if(!region) return; + if(!region || gDisconnected) return; LLTextBox* region_name = getChild<LLTextBox>("region_name_text"); if (region_name) @@ -3170,7 +3178,7 @@ void LLPanelLandExperiences::refreshPanel(LLPanelExperienceListEditor* panel, U3 { return; } - if (parcel == NULL) + if (!parcel || gDisconnected) { // disable the panel panel->setEnabled(FALSE); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a6a9838a3c..576d6e890f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -338,25 +338,25 @@ BOOL LLFloaterModelPreview::postBuild() LLTextBox* text = getChild<LLTextBox>(lod_label_name[i]); if (text) { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + text->setMouseDownCallback(boost::bind(&LLFloaterModelPreview::setPreviewLOD, this, i)); } text = getChild<LLTextBox>(lod_triangles_name[i]); if (text) { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + text->setMouseDownCallback(boost::bind(&LLFloaterModelPreview::setPreviewLOD, this, i)); } text = getChild<LLTextBox>(lod_vertices_name[i]); if (text) { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + text->setMouseDownCallback(boost::bind(&LLFloaterModelPreview::setPreviewLOD, this, i)); } text = getChild<LLTextBox>(lod_status_name[i]); if (text) { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + text->setMouseDownCallback(boost::bind(&LLFloaterModelPreview::setPreviewLOD, this, i)); } } std::string current_grid = LLGridManager::getInstance()->getGridId(); @@ -1363,6 +1363,14 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); } +void LLFloaterModelPreview::setPreviewLOD(S32 lod) +{ + if (mModelPreview) + { + mModelPreview->setPreviewLOD(lod); + } +} + void LLModelPreview::rebuildUploadData() { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index b2bb15ef05..a73ca50260 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -95,6 +95,7 @@ public: static void setUploadAmount(S32 amount) { sUploadAmount = amount; } void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); + void setPreviewLOD(S32 lod); void onBrowseLOD(S32 lod); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index aed3294189..4eacd728c3 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -233,6 +233,11 @@ BOOL LLFloaterRegionInfo::postBuild() panel->buildFromFile("panel_region_debug.xml"); mTab->addTabPanel(panel); + if(gDisconnected) + { + return TRUE; + } + if(!gAgent.getRegion()->getCapability("RegionExperiences").empty()) { panel = new LLPanelRegionExperiences; @@ -256,6 +261,11 @@ LLFloaterRegionInfo::~LLFloaterRegionInfo() void LLFloaterRegionInfo::onOpen(const LLSD& key) { + if(gDisconnected) + { + disableTabCtrls(); + return; + } refreshFromRegion(gAgent.getRegion()); requestRegionInfo(); requestMeshRezInfo(); @@ -479,7 +489,16 @@ LLPanelRegionExperiences* LLFloaterRegionInfo::getPanelExperiences() return (LLPanelRegionExperiences*)tab->getChild<LLPanel>("Experiences"); } +void LLFloaterRegionInfo::disableTabCtrls() +{ + LLTabContainer* tab = getChild<LLTabContainer>("region_panels"); + tab->getChild<LLPanel>("General")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Debug")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Terrain")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("panel_env_info")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Estate")->setCtrlsEnabled(FALSE); +} void LLFloaterRegionInfo::onTabSelected(const LLSD& param) { @@ -1160,6 +1179,22 @@ BOOL LLPanelRegionTerrainInfo::validateTextureSizes() return TRUE; } +BOOL LLPanelRegionTerrainInfo::validateTextureHeights() +{ + for (S32 i = 0; i < CORNER_COUNT; ++i) + { + std::string low = llformat("height_start_spin_%d", i); + std::string high = llformat("height_range_spin_%d", i); + + if (getChild<LLUICtrl>(low)->getValue().asReal() > getChild<LLUICtrl>(high)->getValue().asReal()) + { + return FALSE; + } + } + + return TRUE; +} + ///////////////////////////////////////////////////////////////////////////// // LLPanelRegionTerrainInfo ///////////////////////////////////////////////////////////////////////////// @@ -1192,6 +1227,9 @@ BOOL LLPanelRegionTerrainInfo::postBuild() childSetAction("upload_raw_btn", onClickUploadRaw, this); childSetAction("bake_terrain_btn", onClickBakeTerrain, this); + mAskedTextureHeights = false; + mConfirmedTextureHeights = false; + return LLPanelRegionInfo::postBuild(); } @@ -1274,6 +1312,21 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate() return FALSE; } + // Check if terrain Elevation Ranges are correct + if (gSavedSettings.getBOOL("RegionCheckTextureHeights") && !validateTextureHeights()) + { + if (!mAskedTextureHeights) + { + LLNotificationsUtil::add("ConfirmTextureHeights", LLSD(), LLSD(), boost::bind(&LLPanelRegionTerrainInfo::callbackTextureHeights, this, _1, _2)); + mAskedTextureHeights = true; + return FALSE; + } + else if (!mConfirmedTextureHeights) + { + return FALSE; + } + } + LLTextureCtrl* texture_ctrl; std::string id_str; LLMessageSystem* msg = gMessageSystem; @@ -1314,6 +1367,29 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate() return TRUE; } +bool LLPanelRegionTerrainInfo::callbackTextureHeights(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // ok + { + mConfirmedTextureHeights = true; + } + else if (option == 1) // cancel + { + mConfirmedTextureHeights = false; + } + else if (option == 2) // don't ask + { + gSavedSettings.setBOOL("RegionCheckTextureHeights", FALSE); + mConfirmedTextureHeights = true; + } + + onBtnSet(); + + mAskedTextureHeights = false; + return false; +} + // static void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data) { @@ -3018,6 +3094,11 @@ bool LLPanelEnvironmentInfo::refreshFromRegion(LLViewerRegion* region) void LLPanelEnvironmentInfo::refresh() { + if(gDisconnected) + { + return; + } + populateWaterPresetsList(); populateSkyPresetsList(); populateDayCyclesList(); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 3c74618fff..46f2b42137 100755 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -113,6 +113,7 @@ private: protected: void onTabSelected(const LLSD& param); + void disableTabCtrls(); void refreshFromRegion(LLViewerRegion* region); // member data @@ -240,6 +241,7 @@ public: void setEnvControls(bool available); // Whether environment settings are available for this region BOOL validateTextureSizes(); + BOOL validateTextureHeights(); //static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button @@ -249,6 +251,11 @@ public: static void onClickUploadRaw(void*); static void onClickBakeTerrain(void*); bool callbackBakeTerrain(const LLSD& notification, const LLSD& response); + bool callbackTextureHeights(const LLSD& notification, const LLSD& response); + +private: + bool mConfirmedTextureHeights; + bool mAskedTextureHeights; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index aee20ff706..c7218ad9d5 100755 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -69,7 +69,11 @@ void LLFloaterSidePanelContainer::closeFloater(bool app_quitting) LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel("appearance")); if ( panel_appearance ) { - panel_appearance->getWearable()->onClose(); + LLPanelEditWearable *edit_wearable_ptr = panel_appearance->getWearable(); + if (edit_wearable_ptr) + { + edit_wearable_ptr->onClose(); + } panel_appearance->showOutfitsInventoryPanel(); } } diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index f8681fe098..e20360066e 100755 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -183,10 +183,15 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) msg->getU32("DataExtended", "TimeStamp", time_stamp, block); msg->getF32("DataExtended", "MonoScore", mono_score, block); msg->getS32("DataExtended", "PublicURLs", public_urls, block); - if (msg->getSize("DataExtended", "ParcelName") > 0) + + std::string parcel_name; + F32 script_size = 0.f; + msg->getString("DataExtended", "ParcelName", parcel_name, block); + msg->getF32("DataExtended", "Size", script_size, block); + if (parcel_name.size() > 0 || script_size > 0) { - msg->getString("DataExtended", "ParcelName", parcel_buf, block); - msg->getF32("DataExtended", "Size", script_memory, block); + parcel_buf = parcel_name; + script_memory = script_size; } } diff --git a/indra/newview/llgroupiconctrl.cpp b/indra/newview/llgroupiconctrl.cpp index 1974a073dd..271dd44c1f 100755 --- a/indra/newview/llgroupiconctrl.cpp +++ b/indra/newview/llgroupiconctrl.cpp @@ -64,7 +64,8 @@ LLGroupIconCtrl::LLGroupIconCtrl(const LLGroupIconCtrl::Params& p) } else { - LLIconCtrl::setValue(mDefaultIconName); + //TODO: Consider implementing dedicated setDefault() function instead of passing priority for local file + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); } } @@ -73,6 +74,11 @@ LLGroupIconCtrl::~LLGroupIconCtrl() LLGroupMgr::getInstance()->removeObserver(this); } +void LLGroupIconCtrl::setIconId(const LLSD& value) +{ + LLIconCtrl::setValue(value); +} + void LLGroupIconCtrl::setValue(const LLSD& value) { if (value.isUUID()) @@ -91,7 +97,7 @@ void LLGroupIconCtrl::setValue(const LLSD& value) // Check if cache already contains image_id for that group if (!updateFromCache()) { - LLIconCtrl::setValue(mDefaultIconName); + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); gm->addObserver(this); gm->sendGroupPropertiesRequest(mGroupId); } @@ -122,7 +128,7 @@ bool LLGroupIconCtrl::updateFromCache() } else { - LLIconCtrl::setValue(mDefaultIconName); + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); } if (mDrawTooltip && !group_data->mName.empty()) diff --git a/indra/newview/llgroupiconctrl.h b/indra/newview/llgroupiconctrl.h index f42593c9e1..f8b22cf581 100755 --- a/indra/newview/llgroupiconctrl.h +++ b/indra/newview/llgroupiconctrl.h @@ -66,6 +66,8 @@ public: */ virtual void setValue(const LLSD& value); + void setIconId(const LLSD& value); + // LLGroupMgrObserver observer trigger virtual void changed(LLGroupChange gc); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index ef238cefe3..6126db2988 100755 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -30,7 +30,7 @@ // libs #include "llbutton.h" -#include "lliconctrl.h" +#include "llgroupiconctrl.h" #include "llmenugl.h" #include "lltextbox.h" #include "lltextutil.h" @@ -319,7 +319,7 @@ LLGroupListItem::~LLGroupListItem() //virtual BOOL LLGroupListItem::postBuild() { - mGroupIcon = getChild<LLIconCtrl>("group_icon"); + mGroupIcon = getChild<LLGroupIconCtrl>("group_icon"); mGroupNameBox = getChild<LLTextBox>("group_name"); mInfoBtn = getChild<LLButton>("info_btn"); @@ -381,7 +381,7 @@ void LLGroupListItem::setGroupIconID(const LLUUID& group_icon_id) { if (group_icon_id.notNull()) { - mGroupIcon->setValue(group_icon_id); + mGroupIcon->setIconId(group_icon_id); } } diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index e96a720886..171b77fb00 100755 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -83,7 +83,7 @@ private: }; class LLButton; -class LLIconCtrl; +class LLGroupIconCtrl; class LLTextBox; class LLGroupListItem : public LLPanel @@ -113,7 +113,7 @@ private: LLTextBox* mGroupNameBox; LLUUID mGroupID; - LLIconCtrl* mGroupIcon; + LLGroupIconCtrl* mGroupIcon; LLButton* mInfoBtn; std::string mGroupName; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1782653439..26c9b40fb1 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1958,6 +1958,7 @@ BOOL LLItemBridge::removeItem() } LLNotifications::instance().forceResponse(params, 0); + model->checkTrashOverflow(); return TRUE; } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index bdbe253723..cada2d7cf2 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -44,6 +44,7 @@ #include "llmarketplacefunctions.h" #include "llwindow.h" #include "llviewercontrol.h" +#include "llviewernetwork.h" #include "llpreview.h" #include "llviewermessage.h" #include "llviewerfoldertype.h" @@ -73,7 +74,8 @@ BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; ///---------------------------------------------------------------------------- //BOOL decompress_file(const char* src_filename, const char* dst_filename); -static const char CACHE_FORMAT_STRING[] = "%s.inv"; +static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.inv"; +static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.inv"; static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess @@ -759,6 +761,22 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } +U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(id, cats, items, LLInventoryModel::INCLUDE_TRASH); + + U32 items_found = items.size() + cats.size(); + + for (U32 i = 0; i < cats.size() && items_found <= max_item_limit; ++i) + { + items_found += getDescendentsCountRecursive(cats[i]->getUUID(), max_item_limit - items_found); + } + + return items_found; +} + void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { const LLInventoryObject *obj = getObject(object_id); @@ -1607,6 +1625,29 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const return cat->fetch(); } +//static +std::string LLInventoryModel::getInvCacheAddres(const LLUUID& owner_id) +{ + std::string inventory_addr; + std::string owner_id_str; + owner_id.toString(owner_id_str); + std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); + if (LLGridManager::getInstance()->isInProductionGrid()) + { + inventory_addr = llformat(PRODUCTION_CACHE_FORMAT_STRING, path.c_str()); + } + else + { + // NOTE: The inventory cache filenames now include the grid name. + // Add controls against directory traversal or problematic pathname lengths + // if your viewer uses grid names from an untrusted source. + const std::string& grid_id_str = LLGridManager::getInstance()->getGridId(); + const std::string& grid_id_lower = utf8str_tolower(grid_id_str); + inventory_addr = llformat(GRID_CACHE_FORMAT_STRING, path.c_str(), grid_id_lower.c_str()); + } + return inventory_addr; +} + void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) @@ -1627,11 +1668,7 @@ void LLInventoryModel::cache( items, INCLUDE_TRASH, can_cache); - std::string agent_id_str; - std::string inventory_filename; - agent_id.toString(agent_id_str); - std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, agent_id_str)); - inventory_filename = llformat(CACHE_FORMAT_STRING, path.c_str()); + std::string inventory_filename = getInvCacheAddres(agent_id); saveToFile(inventory_filename, categories, items); std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); @@ -1935,11 +1972,7 @@ bool LLInventoryModel::loadSkeleton( item_array_t items; item_array_t possible_broken_links; cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. - std::string owner_id_str; - owner_id.toString(owner_id_str); - std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); - std::string inventory_filename; - inventory_filename = llformat(CACHE_FORMAT_STRING, path.c_str()); + std::string inventory_filename = getInvCacheAddres(owner_id); const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); @@ -3320,6 +3353,7 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) //---------------------------------------------------------------------------- // Trash: LLFolderType::FT_TRASH, "ConfirmEmptyTrash" +// Trash: LLFolderType::FT_TRASH, "TrashIsFull" when trash exceeds maximum capacity // Lost&Found: LLFolderType::FT_LOST_AND_FOUND, "ConfirmEmptyLostAndFound" bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type) @@ -3401,10 +3435,17 @@ void LLInventoryModel::removeCategory(const LLUUID& category_id) changeCategoryParent(cat, trash_id, TRUE); } } + + checkTrashOverflow(); } void LLInventoryModel::removeObject(const LLUUID& object_id) { + if(object_id.isNull()) + { + return; + } + LLInventoryObject* obj = getObject(object_id); if (dynamic_cast<LLViewerInventoryItem*>(obj)) { @@ -3426,6 +3467,16 @@ void LLInventoryModel::removeObject(const LLUUID& object_id) } } +void LLInventoryModel::checkTrashOverflow() +{ + static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity"); + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (getDescendentsCountRecursive(trash_id, trash_max_capacity) >= trash_max_capacity) + { + gInventory.emptyFolderType("TrashIsFull", LLFolderType::FT_TRASH); + } +} + const LLUUID &LLInventoryModel::getRootFolderID() const { return mRootFolderID; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index e1e6db19eb..3004eaf7c1 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -164,7 +164,9 @@ public: bool loadSkeleton(const LLSD& options, const LLUUID& owner_id); void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations void createCommonSystemCategories(); - + + static std::string getInvCacheAddres(const LLUUID& owner_id); + // Call on logout to save a terse representation. void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id); private: @@ -262,6 +264,9 @@ public: // Follow parent chain to the top. bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; + +private: + U32 getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit); //-------------------------------------------------------------------- // Find @@ -403,6 +408,8 @@ public: /// removeItem() or removeCategory(), whichever is appropriate void removeObject(const LLUUID& object_id); + void checkTrashOverflow(); + protected: void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 6c81378622..72ec092ed4 100755 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -306,6 +306,12 @@ void LLInventoryFetchItemsObserver::startFetch() continue; } + if ((*it).isNull()) + { + LL_WARNS("Inventory") << "Skip fetching for a NULL uuid" << LL_ENDL; + continue; + } + // It's incomplete, so put it on the incomplete container, and // pack this on the message. mIncomplete.push_back(*it); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 02d378bc51..f5dcbf838d 100755 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1332,6 +1332,11 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L } else { + LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory"); + if (floater_inventory) + { + floater_inventory->setFocus(TRUE); + } active_panel->setSelection(obj_id, TAKE_FOCUS_YES); } } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 366b9ac034..aa934f95a1 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -135,7 +135,7 @@ LLLocalBitmap::~LLLocalBitmap() } // delete self from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_DISCARD); + LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD); gTextureList.deleteImage(image); if (image) @@ -207,7 +207,7 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); texture->ref(); - gTextureList.addImage(texture, TEX_LIST_DISCARD); + gTextureList.addImage(texture, TEX_LIST_STANDARD); if (optional_firstupdate != UT_FIRSTUSE) { @@ -215,7 +215,7 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) replaceIDs(old_id, mWorldID); // remove old_id from gimagelist - LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_DISCARD); + LLViewerFetchedTexture* image = gTextureList.findImage(old_id, TEX_LIST_STANDARD); if (image != NULL) { gTextureList.deleteImage(image); @@ -384,7 +384,7 @@ void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id) std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id, U32 channel) { std::vector<LLViewerObject*> obj_list; - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_DISCARD); + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) { @@ -502,7 +502,7 @@ void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id) { - LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_DISCARD); + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id, TEX_LIST_STANDARD); for(U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(); volume_iter++) { LLVOVolume* volume_to_object = (*old_texture->getVolumeList())[volume_iter]; diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 85faa70552..3cbe742e3c 100755 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -2081,7 +2081,7 @@ BOOL LLManipScale::canAffectSelection() { LLViewerObject *root_object = (objectp == NULL) ? NULL : objectp->getRootEdit(); return objectp->permModify() && objectp->permMove() && !objectp->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced()) && + (root_object == NULL || (!root_object->isPermanentEnforced() && !root_object->isSeat())) && !objectp->isSeat(); } } func; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index dfa33b37ef..6cc7a0fc99 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -795,6 +795,15 @@ void LLMarketplaceData::getMerchantStatusCoro() log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated")); setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); } + else if (httpCode == HTTP_INTERNAL_ERROR) + { + // 499 includes timeout and ssl error - marketplace is down or having issues, we do not show it in this request according to MAINT-5938 + LL_WARNS("SLM") << "SLM Merchant Request failed with status: " << httpCode + << ", reason : " << status.toString() + << ", code : " << result["error_code"].asString() + << ", description : " << result["error_description"].asString() << LL_ENDL; + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + } else { std::string err_code = result["error_code"].asString(); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 8c4849d28d..84a2cd8be1 100755 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -44,6 +44,7 @@ #include "lllocationinputctrl.h" #include "llpaneltopinfobar.h" #include "llteleporthistory.h" +#include "llresizebar.h" #include "llsearchcombobox.h" #include "llslurl.h" #include "llurlregistry.h" @@ -267,7 +268,10 @@ LLNavigationBar::LLNavigationBar() mBtnForward(NULL), mBtnHome(NULL), mCmbLocation(NULL), - mSaveToLocationHistory(false) + mSaveToLocationHistory(false), + mNavigationPanel(NULL), + mFavoritePanel(NULL), + mNavPanWidth(0) { buildFromFile( "panel_navigation_bar.xml"); @@ -286,7 +290,7 @@ BOOL LLNavigationBar::postBuild() mBtnBack = getChild<LLPullButton>("back_btn"); mBtnForward = getChild<LLPullButton>("forward_btn"); mBtnHome = getChild<LLButton>("home_btn"); - + mCmbLocation= getChild<LLLocationInputCtrl>("location_combo"); mBtnBack->setEnabled(FALSE); @@ -318,6 +322,11 @@ BOOL LLNavigationBar::postBuild() LLHints::registerHintTarget("nav_bar", getHandle()); + mNavigationPanel = getChild<LLLayoutPanel>("navigation_layout_panel"); + mFavoritePanel = getChild<LLLayoutPanel>("favorites_layout_panel"); + mNavigationPanel->getResizeBar()->setResizeListener(boost::bind(&LLNavigationBar::onNavbarResized, this)); + mFavoritePanel->getResizeBar()->setResizeListener(boost::bind(&LLNavigationBar::onNavbarResized, this)); + return TRUE; } @@ -356,7 +365,6 @@ BOOL LLNavigationBar::handleRightMouseDown(S32 x, S32 y, MASK mask) show_navbar_context_menu(this,x,y); handled = true; } - return handled; } @@ -365,6 +373,18 @@ void LLNavigationBar::onBackButtonClicked() LLTeleportHistory::getInstance()->goBack(); } +void LLNavigationBar::onNavbarResized() +{ + S32 new_nav_pan_width = mNavigationPanel->getRect().getWidth(); + if(mNavPanWidth != new_nav_pan_width) + { + S32 new_stack_width = new_nav_pan_width + mFavoritePanel->getRect().getWidth(); + F32 ratio = (F32)new_nav_pan_width / (F32)new_stack_width; + gSavedPerAccountSettings.setF32("NavigationBarRatio", ratio); + mNavPanWidth = new_nav_pan_width; + } +} + void LLNavigationBar::onBackOrForwardButtonHeldDown(LLUICtrl* ctrl, const LLSD& param) { if (param["count"].asInteger() == 0) @@ -667,8 +687,18 @@ void LLNavigationBar::handleLoginComplete() LLTeleportHistory::getInstance()->handleLoginComplete(); LLPanelTopInfoBar::instance().handleLoginComplete(); mCmbLocation->handleLoginComplete(); + resizeLayoutPanel(); } +void LLNavigationBar::resizeLayoutPanel() +{ + LLRect nav_bar_rect = mNavigationPanel->getRect(); + + S32 nav_panel_width = (nav_bar_rect.getWidth() + mFavoritePanel->getRect().getWidth()) * gSavedPerAccountSettings.getF32("NavigationBarRatio"); + + nav_bar_rect.setLeftTopAndSize(nav_bar_rect.mLeft, nav_bar_rect.mTop, nav_panel_width, nav_bar_rect.getHeight()); + mNavigationPanel->handleReshape(nav_bar_rect,true); +} void LLNavigationBar::invokeSearch(std::string search_text) { LLFloaterReg::showInstance("search", LLSD().with("category", "all").with("query", LLSD(search_text))); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 7878bab24e..29dbaedf7a 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -29,6 +29,7 @@ #include "llpanel.h" #include "llbutton.h" +#include "lllayoutstack.h" class LLLocationInputCtrl; class LLMenuGL; @@ -108,6 +109,7 @@ private: void rebuildTeleportHistoryMenu(); void showTeleportHistoryMenu(LLUICtrl* btn_ctrl); void invokeSearch(std::string search_text); + void resizeLayoutPanel(); // callbacks void onTeleportHistoryMenuItemClicked(const LLSD& userdata); void onTeleportHistoryChanged(); @@ -120,6 +122,7 @@ private: void onLocationPrearrange(const LLSD& data); void onTeleportFinished(const LLVector3d& global_agent_pos); void onTeleportFailed(); + void onNavbarResized(); void onRegionNameResponse( std::string typed_location, std::string region_name, @@ -135,6 +138,7 @@ private: } } + S32 mNavPanWidth; LLMenuGL* mTeleportHistoryMenu; LLPullButton* mBtnBack; LLPullButton* mBtnForward; @@ -142,6 +146,8 @@ private: LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; + LLLayoutPanel* mNavigationPanel; + LLLayoutPanel* mFavoritePanel; boost::signals2::connection mTeleportFailedConnection; boost::signals2::connection mTeleportFinishConnection; boost::signals2::connection mHistoryMenuConnection; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 551495c6ad..ec2d37c30d 100755 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2214,7 +2214,7 @@ void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical) LLTextureEntry *te = object->getTE(te_index); if (te) { - LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_DISCARD) : NULL; + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; if(!tex) { tex = LLViewerFetchedTexture::sDefaultImagep; diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp index a88a55ab22..6c40499208 100644 --- a/indra/newview/llpanelgroupexperiences.cpp +++ b/indra/newview/llpanelgroupexperiences.cpp @@ -30,7 +30,7 @@ #include "lluictrlfactory.h" #include "roles_constants.h" - +#include "llappviewer.h" #include "llagent.h" #include "llviewerregion.h" #include "llflatlistview.h" @@ -67,7 +67,7 @@ BOOL LLPanelGroupExperiences::postBuild() void LLPanelGroupExperiences::activate() { - if (getGroupID() == LLUUID::null) + if ((getGroupID() == LLUUID::null) || gDisconnected) { return; } diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 263c73dc0e..6e677bbce5 100755 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -1080,28 +1080,25 @@ void LLPanelPermissions::setAllSaleInfo() LLSaleInfo new_sale_info(sale_type, price); LLSelectMgr::getInstance()->selectionSetObjectSaleInfo(new_sale_info); - - U8 old_click_action = 0; - LLSelectMgr::getInstance()->selectionGetClickAction(&old_click_action); - if (old_sale_info.isForSale() - && !new_sale_info.isForSale() - && old_click_action == CLICK_ACTION_BUY) - { - // If turned off for-sale, make sure click-action buy is turned - // off as well - LLSelectMgr::getInstance()-> - selectionSetClickAction(CLICK_ACTION_TOUCH); - } - else if (new_sale_info.isForSale() - && !old_sale_info.isForSale() - && old_click_action == CLICK_ACTION_TOUCH) - { - // If just turning on for-sale, preemptively turn on one-click buy - // unless user have a different click action set - LLSelectMgr::getInstance()-> - selectionSetClickAction(CLICK_ACTION_BUY); - } + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + return object->getClickAction() == CLICK_ACTION_BUY + || object->getClickAction() == CLICK_ACTION_TOUCH; + } + } check_actions; + + // Selection should only contain objects that are of target + // action already or of action we are aiming to remove. + bool default_actions = LLSelectMgr::getInstance()->getSelection()->applyToObjects(&check_actions); + + if (default_actions && old_sale_info.isForSale() != new_sale_info.isForSale()) + { + U8 new_click_action = new_sale_info.isForSale() ? CLICK_ACTION_BUY : CLICK_ACTION_TOUCH; + LLSelectMgr::getInstance()->selectionSetClickAction(new_click_action); + } } struct LLSelectionPayable : public LLSelectedObjectFunctor diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 9e4f50b7a7..9c0222d0bc 100755 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -123,11 +123,28 @@ void LLPersistentNotificationStorage::loadNotifications() LLNotifications& instance = LLNotifications::instance(); S32 processed_notifications = 0; + std::vector<LLSD> notifications_array; for (LLSD::reverse_array_iterator notification_it = data.rbeginArray(); notification_it != data.rendArray(); ++notification_it) { LLSD notification_params = *notification_it; + notifications_array.push_back(notification_params); + + ++processed_notifications; + if (processed_notifications >= gSavedSettings.getS32("MaxPersistentNotifications")) + { + LL_WARNS() << "Too many persistent notifications." + << " Processed " << gSavedSettings.getS32("MaxPersistentNotifications") << " of " << data.size() << " persistent notifications." << LL_ENDL; + break; + } + } + + for (LLSD::reverse_array_iterator notification_it = notifications_array.rbegin(); + notification_it != notifications_array.rend(); + ++notification_it) + { + LLSD notification_params = *notification_it; LLNotificationPtr notification(new LLNotification(notification_params)); LLNotificationResponderPtr responder(createResponder(notification_params["name"], notification_params["responder"])); @@ -143,14 +160,8 @@ void LLPersistentNotificationStorage::loadNotifications() // hide saved toasts so they don't confuse the user notification_channel->hideToast(notification->getID()); } - ++processed_notifications; - if (processed_notifications >= gSavedSettings.getS32("MaxPersistentNotifications")) - { - LL_WARNS() << "Too many persistent notifications." - << " Processed " << gSavedSettings.getS32("MaxPersistentNotifications") << " of " << data.size() << " persistent notifications." << LL_ENDL; - break; - } } + LLNotifications::instance().getChannel("Persistent")-> connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1)); LL_INFOS("LLPersistentNotificationStorage") << "finished loading notifications" << LL_ENDL; diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index ea7cf82674..86135ee6e8 100755 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -198,7 +198,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility) if (is_outfit_edit_visible || is_wearable_edit_visible) { - const LLViewerWearable *wearable_ptr = mEditWearable->getWearable(); + const LLViewerWearable *wearable_ptr = mEditWearable ? mEditWearable->getWearable() : NULL; if (!wearable_ptr) { LL_WARNS() << "Visibility change to invalid wearable" << LL_ENDL; diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 503dd6747d..cb356726e6 100755 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -718,7 +718,6 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL << " quant_wbits " << (S32)ph.quant_wbits << " patchids " << (S32)ph.patchids << LL_ENDL; - LLAppViewer::instance()->badNetworkHandler(); return; } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index bcdf8360ed..37cc908e84 100755 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1491,6 +1491,7 @@ void LLTextureCache::readHeaderCache() new_entries.push_back(entry); } } + mFreeList.clear(); // recreating list, no longer valid. llassert_always(new_entries.size() <= sCacheMaxEntries); mHeaderEntriesInfo.mEntries = new_entries.size(); writeEntriesHeader(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 980810835e..e5aa740a33 100755 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1393,7 +1393,7 @@ void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb) void LLTextureCtrl::setImageAssetName(const std::string& name) { - LLPointer<LLUIImage> imagep = LLUI::getUIImage(name); + LLPointer<LLUIImage> imagep = LLUI::getUIImage(name, LLGLTexture::BOOST_PREVIEW); if(imagep) { LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get()); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 750140245b..a0e112c5e8 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -4449,7 +4449,7 @@ void LLTextureFetchDebugger::addHistoryEntry(LLTextureFetchWorker* worker) mRefetchedAllData += worker->mFormattedImage->getDataSize(); // refetch list only requests/creates normal images, so requesting ui='false' - LLViewerFetchedTexture* tex = LLViewerTextureManager::findFetchedTexture(worker->mID, TEX_LIST_DISCARD); + LLViewerFetchedTexture* tex = LLViewerTextureManager::findFetchedTexture(worker->mID, TEX_LIST_STANDARD); if(tex && mRefetchList[tex].begin() != mRefetchList[tex].end()) { if(worker->mDecodedDiscard == mFetchingHistory[mRefetchList[tex][0]].mDecodedLevel) diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 63ede7f8ac..7020ac0c65 100755 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -380,10 +380,6 @@ void LLToast::setVisible(BOOL show) { mTimer->start(); } - if (!getVisible()) - { - LLModalDialog::setFrontmost(FALSE); - } } else { diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 530bd9a18f..bbce717c20 100755 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -181,6 +181,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal params.wrap(true); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); params.allow_scroll(true); + params.force_urls_external(mNotification->getForceUrlsExternal()); LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params); // Compute max allowable height for the dialog text, so we can allocate diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index cafe757c1a..f6ca0bc9d7 100755 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -31,7 +31,7 @@ #include "llfocusmgr.h" #include "llbutton.h" -#include "lliconctrl.h" +#include "llgroupiconctrl.h" #include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "llnotifications.h" @@ -65,8 +65,10 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi } //group icon - LLIconCtrl* pGroupIcon = getChild<LLIconCtrl>("group_icon", TRUE); - pGroupIcon->setValue(groupData.mInsigniaID); + LLGroupIconCtrl* pGroupIcon = getChild<LLGroupIconCtrl>("group_icon", TRUE); + + // We should already have this data preloaded, so no sense in setting icon through setValue(group_id) + pGroupIcon->setIconId(groupData.mInsigniaID); //header title std::string from_name = payload["sender_name"].asString(); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 3e027e3d05..a7ad7c80d9 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1312,6 +1312,13 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && media_instance->getMediaPlugin()) { + // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the + // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. + // For now, we use the URL for the OpenID POST request since it will have the same authority + // as the domain field. + // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) + url = std::string(sOpenIDURL.mURI) + "://" + std::string(sOpenIDURL.mAuthority); + media_instance->getMediaPlugin()->setCookie(url, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure); } } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e43a6d2b8f..66eee552be 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2362,6 +2362,20 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s } } +const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); +const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); +void translate_if_needed(std::string& message) +{ + if (message == NOT_ONLINE_MSG) + { + message = LLTrans::getString("not_online_msg"); + } + else if (message == NOT_ONLINE_INVENTORY) + { + message = LLTrans::getString("not_online_inventory"); + } +} + void process_improved_im(LLMessageSystem *msg, void **user_data) { LLUUID from_id; @@ -2426,6 +2440,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) chat.mFromID = from_id; chat.mFromName = name; chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT; + + if (chat.mSourceType == CHAT_SOURCE_SYSTEM) + { // Translate server message if required (MAINT-6109) + translate_if_needed(message); + } LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. if (source) @@ -5598,6 +5617,10 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) bool you_paid_someone = (source_id == gAgentID); if (you_paid_someone) { + if(!gSavedSettings.getBOOL("NotifyMoneySpend")) + { + return; + } args["NAME"] = dest_slurl; is_name_group = is_dest_group; name_id = dest_id; @@ -5635,6 +5658,10 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) } else { // ...someone paid you + if(!gSavedSettings.getBOOL("NotifyMoneyReceived")) + { + return; + } args["NAME"] = source_slurl; is_name_group = is_source_group; name_id = source_id; @@ -7419,7 +7446,7 @@ void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool args["URL"] = load_url_info["url"].asString(); args["MESSAGE"] = load_url_info["message"].asString();; args["OBJECTNAME"] = load_url_info["object_name"].asString(); - args["NAME"] = owner_name; + args["NAME_SLURL"] = LLSLURL(is_group ? "group" : "agent", id, "about").getSLURLString(); LLNotificationsUtil::add("LoadWebPage", args, load_url_info); } diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 03c3f0fc08..023f1b92ba 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1201,6 +1201,12 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh bounds[0].add(*shift); } + F32 OCCLUSION_FUDGE_Z = SG_OCCLUSION_FUDGE; //<-- #Solution #2 + if (LLDrawPool::POOL_WATER == mSpatialPartition->mDrawableType) + { + OCCLUSION_FUDGE_Z = 1.; + } + // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension if (earlyFail(camera, bounds)) { @@ -1260,7 +1266,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, bounds[0].getF32ptr()); shader->uniform3f(LLShaderMgr::BOX_SIZE, bounds[1][0]+SG_OCCLUSION_FUDGE, bounds[1][1]+SG_OCCLUSION_FUDGE, - bounds[1][2]+SG_OCCLUSION_FUDGE); + bounds[1][2]+OCCLUSION_FUDGE_Z); if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { @@ -1270,7 +1276,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { @@ -1283,7 +1289,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index e2b8ff8e80..c5e07f009f 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -716,7 +716,8 @@ void LLViewerTexture::setBoostLevel(S32 level) { mBoostLevel = level; if(mBoostLevel != LLViewerTexture::BOOST_NONE && - mBoostLevel != LLViewerTexture::BOOST_SELECTED) + mBoostLevel != LLViewerTexture::BOOST_SELECTED && + mBoostLevel != LLViewerTexture::BOOST_ICON) { setNoDelete(); } @@ -3322,7 +3323,7 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL setCategory(LLGLTexture::MEDIA); - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD); + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { tex->setParcelMedia(this); @@ -3332,7 +3333,7 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL //virtual LLViewerMediaTexture::~LLViewerMediaTexture() { - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD); + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { tex->setParcelMedia(NULL); @@ -3387,7 +3388,7 @@ BOOL LLViewerMediaTexture::findFaces() BOOL ret = TRUE; - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_DISCARD); + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) @@ -3496,7 +3497,7 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) const LLTextureEntry* te = facep->getTextureEntry(); if(te && te->getID().notNull()) { - LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_DISCARD); + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); if(tex) { mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. @@ -3525,7 +3526,7 @@ void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) const LLTextureEntry* te = facep->getTextureEntry(); if(te && te->getID().notNull()) { - LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_DISCARD); + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); if(tex) { for(std::list< LLPointer<LLViewerTexture> >::iterator iter = mTextureList.begin(); @@ -3634,10 +3635,10 @@ void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) const LLTextureEntry* te = facep->getTextureEntry(); if(te) { - LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_DISCARD) : NULL; + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; if(!tex && te->getID() != mID)//try parcel media. { - tex = gTextureList.findImage(mID, TEX_LIST_DISCARD); + tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); } if(!tex) { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 9ee5ed758f..5cfd04b4c1 100755 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -72,20 +72,14 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images"); ETexListType get_element_type(S32 priority) { - // don't discard flag can be used in some cases, but it usually is not set yet - if (priority == LLViewerFetchedTexture::BOOST_ICON - || priority == LLViewerFetchedTexture::BOOST_UI) - { - return TEX_LIST_UI; - } - return TEX_LIST_DISCARD; + return (priority == LLViewerFetchedTexture::BOOST_ICON) ? TEX_LIST_SCALE : TEX_LIST_STANDARD; } /////////////////////////////////////////////////////////////////////////////// LLTextureKey::LLTextureKey() : textureId(LLUUID::null), -textureType(TEX_LIST_DISCARD) +textureType(TEX_LIST_STANDARD) { } @@ -450,10 +444,16 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& if (boost_priority != 0) { - if (boost_priority == LLViewerFetchedTexture::BOOST_UI - || boost_priority == LLViewerFetchedTexture::BOOST_ICON) + if (boost_priority == LLViewerFetchedTexture::BOOST_UI) + { + imagep->dontDiscard(); + } + if (boost_priority == LLViewerFetchedTexture::BOOST_ICON) { + // Agent and group Icons are downloadable content, nothing manages + // icon deletion yet, so they should not persist imagep->dontDiscard(); + imagep->forceActive(); } imagep->setBoostLevel(boost_priority); } @@ -554,10 +554,16 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, if (boost_priority != 0) { - if (boost_priority == LLViewerFetchedTexture::BOOST_UI - || boost_priority == LLViewerFetchedTexture::BOOST_ICON) + if (boost_priority == LLViewerFetchedTexture::BOOST_UI) + { + imagep->dontDiscard(); + } + if (boost_priority == LLViewerFetchedTexture::BOOST_ICON) { + // Agent and group Icons are downloadable content, nothing manages + // icon deletion yet, so they should not persist. imagep->dontDiscard(); + imagep->forceActive(); } imagep->setBoostLevel(boost_priority); } @@ -579,7 +585,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output) { - LLTextureKey search_key(image_id, TEX_LIST_DISCARD); + LLTextureKey search_key(image_id, TEX_LIST_STANDARD); uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key); while (iter != mUUIDMap.end() && iter->first.textureId == image_id) { @@ -1585,14 +1591,14 @@ void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void ** LLUUID image_id; msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); - LLViewerFetchedTexture* image = gTextureList.findImage( image_id, TEX_LIST_DISCARD); + LLViewerFetchedTexture* image = gTextureList.findImage( image_id, TEX_LIST_STANDARD); if( image ) { LL_WARNS() << "Image not in db" << LL_ENDL; image->setIsMissingAsset(); } - image = gTextureList.findImage(image_id, TEX_LIST_UI); + image = gTextureList.findImage(image_id, TEX_LIST_SCALE); if (image) { LL_WARNS() << "Icon not in db" << LL_ENDL; diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 9f94f2f1bc..ba76770838 100755 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -61,8 +61,8 @@ typedef void (*LLImageCallback)(BOOL success, enum ETexListType { - TEX_LIST_DISCARD = 0, - TEX_LIST_UI + TEX_LIST_STANDARD = 0, + TEX_LIST_SCALE }; struct LLTextureKey diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f96c4b7bf0..50329d8576 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1037,7 +1037,16 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { - BOOL down = TRUE; + mAllowMouseDragging = FALSE; + if (!mMouseDownTimer.getStarted()) + { + mMouseDownTimer.start(); + } + else + { + mMouseDownTimer.reset(); + } + BOOL down = TRUE; return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); } @@ -1056,7 +1065,11 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - BOOL down = FALSE; + if (mMouseDownTimer.getStarted()) + { + mMouseDownTimer.stop(); + } + BOOL down = FALSE; return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); } @@ -1288,6 +1301,22 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask } } +void LLViewerWindow::handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask) +{ + if (mMouseDownTimer.getStarted()) + { + if (mMouseDownTimer.getElapsedTimeF32() > 0.1) + { + mAllowMouseDragging = TRUE; + mMouseDownTimer.stop(); + } + } + if(mAllowMouseDragging || !LLToolCamera::getInstance()->hasMouseCapture()) + { + handleMouseMove(window, pos, mask); + } +} + void LLViewerWindow::handleMouseLeave(LLWindow *window) { // Note: we won't get this if we have captured the mouse. @@ -1617,6 +1646,8 @@ LLViewerWindow::LLViewerWindow(const Params& p) mMiddleMouseDown(FALSE), mRightMouseDown(FALSE), mMouseInWindow( FALSE ), + mAllowMouseDragging(TRUE), + mMouseDownTimer(), mLastMask( MASK_NONE ), mToolStored( NULL ), mHideCursorPermanent( FALSE ), @@ -4951,6 +4982,13 @@ void LLViewerWindow::stopGL(BOOL save_state) gGLManager.mIsDisabled = TRUE; stop_glerror(); + + //unload shader's + while (LLGLSLShader::sInstances.size()) + { + LLGLSLShader* shader = *(LLGLSLShader::sInstances.begin()); + shader->unload(); + } LL_INFOS() << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemory.value() << " bytes" << LL_ENDL; } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index d34e76f6f6..ad06f00234 100755 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -193,6 +193,7 @@ public: /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); + void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleMouseLeave(LLWindow *window); /*virtual*/ void handleResize(LLWindow *window, S32 x, S32 y); /*virtual*/ void handleFocus(LLWindow *window); @@ -463,6 +464,8 @@ private: BOOL mMouseInWindow; // True if the mouse is over our window or if we have captured the mouse. BOOL mFocusCycleMode; + BOOL mAllowMouseDragging; + LLFrameTimer mMouseDownTimer; typedef std::set<LLHandle<LLView> > view_handle_set_t; view_handle_set_t mMouseHoverViews; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 21c38e9bc1..ddf60b9464 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1992,7 +1992,7 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU uuid == IMG_INVISIBLE) { // Should already exist, don't need to find it on sim or baked-texture host. - result = gTextureList.findImage(uuid, TEX_LIST_DISCARD); + result = gTextureList.findImage(uuid, TEX_LIST_STANDARD); } if (!result) { @@ -4313,7 +4313,7 @@ bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const { for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep && imagep->getDiscardLevel()!=0) { return false; @@ -4385,7 +4385,7 @@ S32Bytes LLVOAvatar::totalTextureMemForUUIDS(std::set<LLUUID>& ids) S32Bytes result(0); for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep) { result += imagep->getTextureMemory(); @@ -4473,7 +4473,7 @@ void LLVOAvatar::releaseOldTextures() { if (new_texture_ids.find(*it) == new_texture_ids.end()) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_DISCARD); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep) { current_texture_mem += imagep->getTextureMemory(); @@ -7975,6 +7975,13 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara // show the cloned params inside the wearables as well. gAgentAvatarp->dumpWearableInfo(outfile); } + LLSD args; + args["PATH"] = fullpath; + LLNotificationsUtil::add("AppearanceToXMLSaved", args); + } + else + { + LLNotificationsUtil::add("AppearanceToXMLFailed"); } // File will close when handle goes out of scope } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 56c0910983..5c125a236a 100755 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -657,19 +657,25 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if(!mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak")) + if (!mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak") && (key == mPTTKey)) { - bool down = (mPTTKey != KEY_NONE) && gKeyboard->getKeyDown(mPTTKey); - if (down) { inputUserControlState(down); } + bool down = gKeyboard->getKeyDown(mPTTKey); + if (down) + { + inputUserControlState(down); + } } } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if(!mPTTIsMiddleMouse) + if (!mPTTIsMiddleMouse && (key == mPTTKey)) { - bool down = (mPTTKey != KEY_NONE) && gKeyboard->getKeyDown(mPTTKey); - if (down) { inputUserControlState(down); } + bool down = gKeyboard->getKeyDown(mPTTKey); + if (!down) + { + inputUserControlState(down); + } } } void LLVoiceClient::middleMouseState(bool down) diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c9661dfb11..07427e0377 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -80,39 +80,49 @@ extern LLMenuBarGL* gMenuBarView; extern void handle_voice_morphing_subscribe(); -const F32 VOLUME_SCALE_VIVOX = 0.01f; +namespace { + const F32 VOLUME_SCALE_VIVOX = 0.01f; -const F32 SPEAKING_TIMEOUT = 1.f; + const F32 SPEAKING_TIMEOUT = 1.f; -static const std::string VOICE_SERVER_TYPE = "Vivox"; + static const std::string VOICE_SERVER_TYPE = "Vivox"; -// Don't retry connecting to the daemon more frequently than this: -const F32 CONNECT_THROTTLE_SECONDS = 1.0f; + // Don't retry connecting to the daemon more frequently than this: + const F32 CONNECT_THROTTLE_SECONDS = 1.0f; -// Don't send positional updates more frequently than this: -const F32 UPDATE_THROTTLE_SECONDS = 0.5f; + // Don't send positional updates more frequently than this: + const F32 UPDATE_THROTTLE_SECONDS = 0.5f; -const F32 LOGIN_RETRY_SECONDS = 10.0f; -const int MAX_LOGIN_RETRIES = 12; + const F32 LOGIN_ATTEMPT_TIMEOUT = 5.0f; + const int LOGIN_RETRY_MAX = 5; + const F32 LOGIN_RETRY_TIMEOUT = 4.0f; -// Cosine of a "trivially" small angle -const F32 MINUSCULE_ANGLE_COS = 0.999f; + const int PROVISION_RETRY_MAX = 5; + const F32 PROVISION_RETRY_TIMEOUT = 2.0; -// Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine() -// which is treated as normal. The is the number of frames to wait for a channel join before giving up. This was changed -// from the original count of 50 for two reason. Modern PCs have higher frame rates and sometimes the SLVoice process -// backs up processing join requests. There is a log statement that records when channel joins take longer than 100 frames. -const int MAX_NORMAL_JOINING_SPATIAL_NUM = 1500; + // Cosine of a "trivially" small angle + const F32 MINUSCULE_ANGLE_COS = 0.999f; -// How often to check for expired voice fonts in seconds -const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f; -// Time of day at which Vivox expires voice font subscriptions. -// Used to replace the time portion of received expiry timestamps. -static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z"; + const F32 SESSION_JOIN_TIMEOUT = 10.0f; -// Maximum length of capture buffer recordings in seconds. -const F32 CAPTURE_BUFFER_MAX_TIME = 10.f; + // Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine() + // which is treated as normal. The is the number of frames to wait for a channel join before giving up. This was changed + // from the original count of 50 for two reason. Modern PCs have higher frame rates and sometimes the SLVoice process + // backs up processing join requests. There is a log statement that records when channel joins take longer than 100 frames. + const int MAX_NORMAL_JOINING_SPATIAL_NUM = 1500; + // How often to check for expired voice fonts in seconds + const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f; + // Time of day at which Vivox expires voice font subscriptions. + // Used to replace the time portion of received expiry timestamps. + static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z"; + + // Maximum length of capture buffer recordings in seconds. + const F32 CAPTURE_BUFFER_MAX_TIME = 10.f; + + const int ERROR_VIVOX_OBJECT_NOT_FOUND = 1001; + const int ERROR_VIVOX_NOT_LOGGED_IN = 1007; +} static int scale_mic_volume(float volume) { @@ -129,8 +139,6 @@ static int scale_speaker_volume(float volume) } -const int ERROR_VIVOX_OBJECT_NOT_FOUND = 1001; -const int ERROR_VIVOX_NOT_LOGGED_IN = 1007; /////////////////////////////////////////////////////////////////////////////////////////////// @@ -546,7 +554,7 @@ void LLVivoxVoiceClient::voiceControlCoro() // if we hit this and mRelogRequested is true, that indicates // that we attempted to relog into Vivox and were rejected. // Rather than just quit out of voice, we will tear it down (above) - // and then reconstruct the voice connecino from scratch. + // and then reconstruct the voice connecion from scratch. if (mRelogRequested) { while (isGatewayRunning()) @@ -784,13 +792,15 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() if (status == LLCore::HttpStatus(404)) { - if (++retryCount > 5) + if (++retryCount > PROVISION_RETRY_MAX) { - LL_WARNS("Voice") << "Could not access voice provision cap after 5 attempts." << LL_ENDL; + LL_WARNS("Voice") << "Could not access voice provision cap after " << PROVISION_RETRY_MAX << " attempts." << LL_ENDL; return false; } - LL_WARNS("Voice") << "Provision CAP 404. Retrying in 1.0" << LL_ENDL; - llcoro::suspendUntilTimeout(1.0); + + F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast<float>(retryCount)); + LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds." << LL_ENDL; + llcoro::suspendUntilTimeout(timeout); continue; } @@ -888,38 +898,42 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait) bool LLVivoxVoiceClient::loginToVivox() { - int loginRetryCount(0); LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); + LLSD timeoutResult(LLSDMap("login", "timeout")); + + int loginRetryCount(0); + bool response_ok(false); bool account_login(false); bool send_login(true); do { + mIsLoggingIn = true; if (send_login) loginSendMessage(); send_login = false; - LLSD result = llcoro::suspendUntilEventOn(voicePump); + LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; if (result.has("login")) { std::string loginresp = result["login"]; - if (loginresp == "retry") + if ((loginresp == "retry") || (loginresp == "timeout")) { - if (!loginRetryCount) + if ((!loginRetryCount) && (loginresp != "timeout")) { // on first retry notify user notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY); } - if ((++loginRetryCount > MAX_LOGIN_RETRIES) || (!result["login_retry"])) + if ((++loginRetryCount > LOGIN_RETRY_MAX) || (loginresp == "timeout")) { - LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL; + LL_WARNS("Voice") << "too many login retries or timeout connecting, giving up." << LL_ENDL; LLSD args; std::stringstream errs; errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; @@ -942,8 +956,10 @@ bool LLVivoxVoiceClient::loginToVivox() account_login = false; send_login = true; - LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL; - llcoro::suspendUntilTimeout(LOGIN_RETRY_SECONDS); + F32 timeout = pow(LOGIN_RETRY_TIMEOUT, static_cast<float>(loginRetryCount)) - 1.0f; + + LL_INFOS("Voice") << "will retry login in " << timeout << " seconds." << LL_ENDL; + llcoro::suspendUntilTimeout(timeout); } else if (loginresp == "failed") { @@ -982,7 +998,6 @@ bool LLVivoxVoiceClient::loginToVivox() void LLVivoxVoiceClient::logoutOfVivox(bool wait) { - LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); if (!mIsLoggedIn) return; @@ -995,7 +1010,10 @@ void LLVivoxVoiceClient::logoutOfVivox(bool wait) if (wait) { - LLSD result = llcoro::suspendUntilEventOn(voicePump); + LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); + LLSD timeoutResult(LLSDMap("lougout", "timeout")); + + LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; @@ -1169,6 +1187,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) if (!mVoiceEnabled && mIsInitialized) { + LL_DEBUGS("Voice") << "Voice no longer enabled. Exiting." << LL_ENDL; mIsJoiningSession = false; // User bailed out during connect -- jump straight to teardown. terminateAudioSession(true); @@ -1177,6 +1196,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) } else if (mSessionTerminateRequested) { + LL_DEBUGS("Voice") << "Terminate requested" << LL_ENDL; if (mAudioSession && !mAudioSession->mHandle.empty()) { // Only allow direct exits from this state in p2p calls (for cancelling an invite). @@ -1194,15 +1214,17 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) bool added(true); bool joined(false); + LLSD timeoutResult(LLSDMap("session", "timeout")); + // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4 // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck. // For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined. // This is a cheap way to make sure both have happened before proceeding. do { - result = llcoro::suspendUntilEventOn(voicePump); + result = llcoro::suspendUntilEventOnWithTimeout(voicePump, SESSION_JOIN_TIMEOUT, timeoutResult); - LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; + LL_INFOS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; if (result.has("session")) { if (result.has("handle")) @@ -1215,14 +1237,15 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) } std::string message = result["session"].asString(); + if ((message == "added") || (message == "created")) added = true; else if (message == "joined") joined = true; - else if ((message == "failed") || (message == "removed")) + else if ((message == "failed") || (message == "removed") || (message == "timeout")) { // we will get a removed message if a voice call is declined. - if (message == "failed") + if (message == "failed") { int reason = result["reason"].asInteger(); LL_WARNS("Voice") << "Add and join failed for reason " << reason << LL_ENDL; @@ -1230,7 +1253,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) if ((reason == ERROR_VIVOX_NOT_LOGGED_IN) || (reason == ERROR_VIVOX_OBJECT_NOT_FOUND)) { - LL_INFOS("Voice") << "Requesting reprovision and login." << LL_ENDL; + LL_DEBUGS("Voice") << "Requesting reprovision and login." << LL_ENDL; requestRelog(); } @@ -1472,11 +1495,9 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) notifyParticipantObservers(); notifyVoiceFontObservers(); - LLSD timeoutEvent = LLSD::emptyMap(); - timeoutEvent["timeout"] = LLSD::Boolean(true); + LLSD timeoutEvent(LLSDMap("timeout", LLSD::Boolean(true))); LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); - LLEventTimeout timeout(voicePump); mIsInChannel = true; mMuteMicDirty = true; @@ -1528,8 +1549,7 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) sendLocalAudioUpdates(); mIsInitialized = true; - timeout.eventAfter(UPDATE_THROTTLE_SECONDS, timeoutEvent); - LLSD result = llcoro::suspendUntilEventOn(timeout); + LLSD result = llcoro::suspendUntilEventOnWithTimeout(voicePump, UPDATE_THROTTLE_SECONDS, timeoutEvent); if (!result.has("timeout")) // logging the timeout event spams the log LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; if (result.has("session")) @@ -1627,22 +1647,19 @@ void LLVivoxVoiceClient::recordingAndPlaybackMode() int LLVivoxVoiceClient::voiceRecordBuffer() { - LLSD timeoutResult; - timeoutResult["recplay"] = LLSD::String("stop"); + LLSD timeoutResult(LLSDMap("recplay", "stop")); LL_INFOS("Voice") << "Recording voice buffer" << LL_ENDL; LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); - LLEventTimeout timeout(voicePump); - timeout.eventAfter(CAPTURE_BUFFER_MAX_TIME, timeoutResult); LLSD result; captureBufferRecordStartSendMessage(); - notifyVoiceFontObservers(); + do { - result = llcoro::suspendUntilEventOn(voicePump); + result = llcoro::suspendUntilEventOnWithTimeout(voicePump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; } while (!result.has("recplay")); @@ -1660,14 +1677,11 @@ int LLVivoxVoiceClient::voiceRecordBuffer() int LLVivoxVoiceClient::voicePlaybackBuffer() { - LLSD timeoutResult; - timeoutResult["recplay"] = LLSD::String("stop"); + LLSD timeoutResult(LLSDMap("recplay", "stop")); LL_INFOS("Voice") << "Playing voice buffer" << LL_ENDL; LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); - LLEventTimeout timeout(voicePump); - timeout.eventAfter(CAPTURE_BUFFER_MAX_TIME, timeoutResult); LLSD result; do @@ -1682,7 +1696,7 @@ int LLVivoxVoiceClient::voicePlaybackBuffer() // Update UI, should really use a separate callback. notifyVoiceFontObservers(); - result = llcoro::suspendUntilEventOn(voicePump); + result = llcoro::suspendUntilEventOnWithTimeout(voicePump, CAPTURE_BUFFER_MAX_TIME, timeoutResult); LL_DEBUGS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL; } while (!result.has("recplay")); @@ -2902,11 +2916,9 @@ void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statu session->mErrorStatusString = statusString; if(session == mAudioSession) { - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(sessionHandle); - vivoxevent["session"] = LLSD::String("failed"); - vivoxevent["reason"] = LLSD::Integer(statusCode); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) + ("session", "failed") + ("reason", LLSD::Integer(statusCode))); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -2923,10 +2935,8 @@ void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statu { setSessionHandle(session, sessionHandle); } - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(sessionHandle); - vivoxevent["session"] = LLSD::String("created"); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) + ("session", "created")); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -2950,10 +2960,8 @@ void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, session->mErrorStatusString = statusString; if(session == mAudioSession) { - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(sessionHandle); - vivoxevent["session"] = LLSD::String("failed"); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) + ("session", "failed")); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -2971,10 +2979,8 @@ void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, setSessionHandle(session, sessionHandle); } - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(sessionHandle); - vivoxevent["session"] = LLSD::String("added"); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle)) + ("session", "added")); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); @@ -3019,9 +3025,7 @@ void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusStrin LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL; // Should this ever fail? do we care if it does? } - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["logout"] = LLSD::Boolean(true); + LLSD vivoxevent(LLSDMap("logout", LLSD::Boolean(true))); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -3036,9 +3040,7 @@ void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string & mConnected = false; - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["connector"] = LLSD::Boolean(false); + LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false))); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -3146,10 +3148,8 @@ void LLVivoxVoiceClient::joinedAudioSession(const sessionStatePtr_t &session) // This is the session we're joining. if(mIsJoiningSession) { - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(session->mHandle); - vivoxevent["session"] = LLSD::String("joined"); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle)) + ("session", "joined")); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); @@ -3292,10 +3292,8 @@ void LLVivoxVoiceClient::leftAudioSession(const sessionStatePtr_t &session) { if (mAudioSession == session) { - LLSD vivoxevent = LLSD::emptyMap(); - - vivoxevent["handle"] = LLSD::String(session->mHandle); - vivoxevent["session"] = LLSD::String("removed"); + LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle)) + ("session", "removed")); LLEventPumps::instance().post("vivoxClientPump", vivoxevent); } @@ -6150,9 +6148,7 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st { // *TODO: We seem to get multiple events of this type. Should figure a way to advance only after // receiving the last one. - LLSD result = LLSD::emptyMap(); - - result["voice_fonts"] = LLSD::Boolean(true); + LLSD result(LLSDMap("voice_fonts", LLSD::Boolean(true))); LLEventPumps::instance().post("vivoxClientPump", result); } @@ -6325,8 +6321,7 @@ void LLVivoxVoiceClient::recordPreviewBuffer() mCaptureBufferRecording = true; - LLSD result; - result["recplay"] = "record"; + LLSD result(LLSDMap("recplay", "record")); LLEventPumps::instance().post("vivoxClientPump", result); } @@ -6349,8 +6344,7 @@ void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) mPreviewVoiceFont = effect_id; mCaptureBufferPlaying = true; - LLSD result; - result["recplay"] = "playback"; + LLSD result(LLSDMap("recplay", "playback")); LLEventPumps::instance().post("vivoxClientPump", result); } @@ -6359,8 +6353,7 @@ void LLVivoxVoiceClient::stopPreviewBuffer() mCaptureBufferRecording = false; mCaptureBufferPlaying = false; - LLSD result; - result["recplay"] = "quit"; + LLSD result(LLSDMap("recplay", "quit")); LLEventPumps::instance().post("vivoxClientPump", result); } diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index aad3b9d062..3e0f0133dd 100755 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1432,7 +1432,7 @@ Hvis du ikke forlader regionen, vil du blive logget af. [MESSAGE] -Fra objekt: <nolink>[OBJECTNAME]</nolink>, ejer: [NAME]? +Fra objekt: <nolink>[OBJECTNAME]</nolink>, ejer: [NAME_SLURL]? <form name="form"> <button name="Gotopage" text="Gå til side"/> <button name="Cancel" text="Afbryd"/> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index fa7db0a8a3..670d081faf 100755 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2956,7 +2956,7 @@ Wenn Sie in dieser Region bleiben, werden Sie abgemeldet. [MESSAGE] -Von Objekt: <nolink>[OBJECTNAME]</nolink>, Eigentümer: [NAME] +Von Objekt: <nolink>[OBJECTNAME]</nolink>, Eigentümer: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Zur Seite"/> <button name="Cancel" text="Abbrechen"/> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 384ae6bb1e..8391bacf51 100755 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -570,8 +570,7 @@ left="0" top="0" help_topic="land_covenant_tab" - name="land_covenant_panel" - word_wrap="true"> + name="land_covenant_panel"> <panel.string name="can_resell" word_wrap="true"> @@ -1076,7 +1075,7 @@ name="Autoreturn" top_pad="0" width="412" - wrap="true"> + word_wrap="true"> Auto return other Residents' objects (minutes, 0 for off): </text> <line_editor @@ -1461,7 +1460,7 @@ Only large parcels can be listed in search. top="150" name="allow_label5" width="205" - wrap="true"> + word_wrap="true"> Avatars on other parcels can see and chat with avatars on this parcel </text> <check_box diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 0c09906155..f8e346afb9 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -3580,6 +3580,19 @@ Do you really want to bake the current terrain, make it the center for terrain r <notification icon="alertmodal.tga" + name="ConfirmTextureHeights" + type="alertmodal"> +You're about to use low values greater than high ones for Elevation Ranges. Proceed? + <tag>confirm</tag> + <usetemplate + name="yesnocancelbuttons" + yestext="Ok" + notext="Cancel" + canceltext="Don't ask"/> + </notification> + + <notification + icon="alertmodal.tga" name="MaxAllowedAgentOnRegion" type="alertmodal"> You can only have [MAX_AGENTS] Allowed Residents. @@ -3857,9 +3870,10 @@ We have downloaded an update to your [APP_NAME] installation. </notification> <notification - icon="alertmodal.tga" - name="RequiredUpdateDownloadedVerboseDialog" - type="alertmodal"> + icon="alertmodal.tga" + name="RequiredUpdateDownloadedVerboseDialog" + type="alertmodal" + force_urls_external="true"> We have downloaded a required software update. Version [VERSION] [[INFO_URL] Information about this update] @@ -3871,9 +3885,10 @@ We must restart [APP_NAME] to install the update. </notification> <notification - icon="alertmodal.tga" - name="RequiredUpdateDownloadedDialog" - type="alertmodal"> + icon="alertmodal.tga" + name="RequiredUpdateDownloadedDialog" + type="alertmodal" + force_urls_external="true"> We must restart [APP_NAME] to install the update. [[INFO_URL] Information about this update] <tag>confirm</tag> @@ -3913,9 +3928,10 @@ see [[INFO_URL] Information about this update] </notification> <notification - icon="alertmodal.tga" - name="OtherChannelRequiredUpdateDownloadedVerboseDialog" - type="alertmodal"> + icon="alertmodal.tga" + name="OtherChannelRequiredUpdateDownloadedVerboseDialog" + type="alertmodal" + force_urls_external="true"> We have downloaded a required software update. Version [VERSION] This experimental viewer has been replaced by a [NEW_CHANNEL] viewer; @@ -3929,9 +3945,10 @@ We must restart [APP_NAME] to install the update. </notification> <notification - icon="alertmodal.tga" - name="OtherChannelRequiredUpdateDownloadedDialog" - type="alertmodal"> + icon="alertmodal.tga" + name="OtherChannelRequiredUpdateDownloadedDialog" + type="alertmodal" + force_urls_external="true"> We must restart [APP_NAME] to install the update. This experimental viewer has been replaced by a [NEW_CHANNEL] viewer; see [[INFO_URL] Information about this update] @@ -5975,6 +5992,18 @@ Are you sure you want to permanently delete the contents of your Trash? <notification icon="alertmodal.tga" + name="TrashIsFull" + type="alertmodal"> +Your trash is overflowing. This may cause problems logging in. + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="I will empty trash later" + yestext="Empty trash now"/> + </notification> + + <notification + icon="alertmodal.tga" name="ConfirmClearBrowserCache" type="alertmodal"> Are you sure you want to delete your travel, web, and search history? @@ -7520,8 +7549,8 @@ Load web page [URL] ? [MESSAGE] -From object: <nolink>[OBJECTNAME]</nolink>, owner: [NAME] - <tag>confirm</tag> +From object: <nolink>[OBJECTNAME]</nolink>, owner: [NAME_SLURL] + <tag>confirm</tag> <form name="form"> <button index="0" @@ -8261,6 +8290,16 @@ Are you sure you want to close all IMs? name="AttachmentSaved" type="notifytip"> Attachment has been saved. </notification> + + <notification icon="notify.tga" persist="true" + name="AppearanceToXMLSaved" type="notify"> +Appearance has been saved to XML to [PATH] + </notification> + + <notification icon="notifytip.tga" + name="AppearanceToXMLFailed" type="notifytip"> +Failed to save appearance to XML. + </notification> <notification icon="alertmodal.tga" diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item.xml b/indra/newview/skins/default/xui/en/panel_group_list_item.xml index cfe3aeb7c9..e758a8ce30 100755 --- a/indra/newview/skins/default/xui/en/panel_group_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_group_list_item.xml @@ -27,7 +27,7 @@ top="0" visible="false" width="320" /> - <icon + <group_icon height="20" image_name="Generic_Group" name="group_icon" diff --git a/indra/newview/skins/default/xui/en/panel_group_notify.xml b/indra/newview/skins/default/xui/en/panel_group_notify.xml index cded4cf31a..4121acdfb0 100755 --- a/indra/newview/skins/default/xui/en/panel_group_notify.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notify.xml @@ -27,7 +27,7 @@ name="header" top="0" width="305"> - <icon + <group_icon follows="all" height="20" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml index 714dca7fac..93c97ded25 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml @@ -21,12 +21,12 @@ Tell me: </text> <check_box - control_name="NotifyMoneyChange" + control_name="NotifyMoneySpend" height="16" - label="When I spend or get L$" + label="When I spend L$" layout="topleft" left_delta="50" - name="notify_money_change_checkbox" + name="notify_money_spend_checkbox" top_pad="4" width="300" /> <check_box @@ -34,10 +34,18 @@ height="16" label="When my friends log in or out" layout="topleft" - left_delta="0" - name="friends_online_notify_checkbox" - top_pad="4" - width="300" /> + left_delta="150" + name="friends_online_notify_checkbox" + width="300" /> + <check_box + control_name="NotifyMoneyReceived" + height="16" + label="When I get L$" + layout="topleft" + left_delta="-150" + top_pad="4" + name="notify_money_received_checkbox" + width="300" /> <text type="string" length="1" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 6c485c0595..e1b8662ece 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -619,6 +619,7 @@ height="16" increment="0.125" initial_value="160" + min_val="0.125" label=" Trees:" label_width="185" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml index c2e7c706d6..4d20ecb9b6 100755 --- a/indra/newview/skins/default/xui/en/role_actions.xml +++ b/indra/newview/skins/default/xui/en/role_actions.xml @@ -105,9 +105,6 @@ <action description="Always allow 'Create Objects'" longdescription="Members in a Role with this Ability can create objects on a group-owned parcel, even if it's turned off in About Land > Options tab." name="land allow create" value="25" /> - <action description="Always allow 'Create Landmark'" - longdescription="Members in a Role with this Ability can landmark a group-owned parcel, even if it's turned off in About Land > Options tab." - name="land allow landmark" value="26" /> <action description="Allow 'Set Home to Here' on group land" longdescription="Members in a Role with this Ability can use World menu > Landmarks > Set Home to Here on a parcel deeded to this group." name="land allow set home" value="28" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index f2eddbb38e..ff98d2f109 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3530,6 +3530,8 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="IM_unblock_only_groups_friends">To see this message, you must uncheck 'Only friends and groups can call or IM me' in Preferences/Privacy.</string> <string name="OnlineStatus">Online</string> <string name="OfflineStatus">Offline</string> + <string name="not_online_msg">User not online - message will be stored and delivered later.</string> + <string name="not_online_inventory">User not online - inventory has been saved.</string> <!-- voice calls --> <string name="answered_call">Your call has been answered</string> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 1e367b33fc..2aac4458e3 100755 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -2950,7 +2950,7 @@ Si permaneces en esta región serás desconectado. [MESSAGE] -Del objeto: <nolink>[OBJECTNAME]</nolink>, propietario: [NAME] +Del objeto: <nolink>[OBJECTNAME]</nolink>, propietario: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Cargar"/> <button name="Cancel" text="Cancelar"/> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index 29e6fe1979..55a67e1187 100755 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2942,7 +2942,7 @@ Si vous restez dans cette région, vous serez déconnecté(e). [MESSAGE] -Venant de l'objet : <nolink>[OBJECTNAME]</nolink>, propriétaire : [NAME] +Venant de l'objet : <nolink>[OBJECTNAME]</nolink>, propriétaire : [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Charger"/> <button name="Cancel" text="Annuler"/> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 61131b09c3..6aeabcc505 100755 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2947,7 +2947,7 @@ Se rimani qui verrai scollegato da Second Life. [MESSAGE] -Dall'oggetto: <nolink>[OBJECTNAME]</nolink>, proprietario: [NAME] +Dall'oggetto: <nolink>[OBJECTNAME]</nolink>, proprietario: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Caricare"/> <button name="Cancel" text="Annulla"/> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index 5f0ce7a73b..b3b4e06a68 100755 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2990,7 +2990,7 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ [MESSAGE] -送信元のオブジェクト:<nolink>[OBJECTNAME]</nolink>、所有者:[NAME] +送信元のオブジェクト:<nolink>[OBJECTNAME]</nolink>、所有者:[NAME_SLURL] <form name="form"> <button name="Gotopage" text="ページに移動"/> <button name="Cancel" text="取り消し"/> diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index c4a65d92b4..25cc43a6e3 100755 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2493,7 +2493,7 @@ Nastąpi wylogowanie jeżeli zostaniesz w tym regionie. [MESSAGE] -Od obiektu: <nolink>[OBJECTNAME]</nolink>, właściciel właściciel: [NAME]? +Od obiektu: <nolink>[OBJECTNAME]</nolink>, właściciel właściciel: [NAME_SLURL]? <form name="form"> <button name="Gotopage" text="Załaduj"/> <button name="Cancel" text="Anuluj"/> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index a264495404..3a3603307e 100755 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2931,7 +2931,7 @@ Se permanecer aqui, você será desconectado. [MESSAGE] -Do objeto: <nolink>[OBJECTNAME]</nolink>, de: [NAME] +Do objeto: <nolink>[OBJECTNAME]</nolink>, de: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Carregar"/> <button name="Cancel" text="Cancelar"/> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index 70b9a25590..7b024926e2 100755 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -2942,7 +2942,7 @@ http://secondlife.com/download. [MESSAGE] -Из объекта: <nolink>[OBJECTNAME]</nolink>, владелец: [NAME] +Из объекта: <nolink>[OBJECTNAME]</nolink>, владелец: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Перейти на страницу"/> <button name="Cancel" text="Отмена"/> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 0d64b2cae9..18ae202230 100755 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -4223,6 +4223,12 @@ support@secondlife.com. <string name="OfflineStatus"> Оффлайн </string> + <string name="not_online_msg"> + Пользователь оффлайн - сообщение будет сохранено и доставлено позже. + </string> + <string name="not_online_inventory"> + Пользователь оффлайн - инвентарь сохранен. + </string> <string name="answered_call"> На ваш звонок ответили </string> diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml index df22251b3d..9875399b34 100755 --- a/indra/newview/skins/default/xui/tr/notifications.xml +++ b/indra/newview/skins/default/xui/tr/notifications.xml @@ -2942,7 +2942,7 @@ Bu bölgede kalmaya devam ederseniz oturumunuz sonlandırılacak. [MESSAGE] -Kaynak nesne: <nolink>[OBJECTNAME]</nolink>, sahibi: [NAME] +Kaynak nesne: <nolink>[OBJECTNAME]</nolink>, sahibi: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Sayfaya git"/> <button name="Cancel" text="İptal"/> diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml index 0a98101b60..371f5d9b39 100755 --- a/indra/newview/skins/default/xui/zh/notifications.xml +++ b/indra/newview/skins/default/xui/zh/notifications.xml @@ -2932,7 +2932,7 @@ SHA1 指紋:[MD5_DIGEST] [MESSAGE] -來源物件:<nolink>[OBJECTNAME]</nolink>(所有人:[NAME]) +來源物件:<nolink>[OBJECTNAME]</nolink>(所有人:[NAME_SLURL]) <form name="form"> <button name="Gotopage" text="前往頁面"/> <button name="Cancel" text="取消"/> |