diff options
author | Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> | 2024-03-12 18:30:33 +0100 |
---|---|---|
committer | Guru <alexandrgproductengine@lindenlab.com> | 2024-03-18 21:19:57 +0100 |
commit | 15734c19783fc5fc38e5c1cba485d756285161e0 (patch) | |
tree | 00f2c0586781b2abe32baa12ee2bb283b2839fef /indra/llui | |
parent | b40ff113c50afc1e012183928e94b2c86252a61f (diff) |
viewer#961 Add a notification appearing when user tries to insert a disallowed character
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/llfolderview.cpp | 2 | ||||
-rw-r--r-- | indra/llui/lllineeditor.cpp | 75 | ||||
-rw-r--r-- | indra/llui/lllineeditor.h | 12 | ||||
-rw-r--r-- | indra/llui/llmultisliderctrl.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llresmgr.cpp | 14 | ||||
-rw-r--r-- | indra/llui/llsliderctrl.cpp | 2 | ||||
-rw-r--r-- | indra/llui/lltexteditor.cpp | 69 | ||||
-rw-r--r-- | indra/llui/lltexteditor.h | 4 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.cpp | 764 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.h | 83 | ||||
-rw-r--r-- | indra/llui/lltimectrl.cpp | 41 | ||||
-rw-r--r-- | indra/llui/lltimectrl.h | 26 |
12 files changed, 648 insertions, 446 deletions
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index cbe8cf2dac..23891cad7f 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -220,7 +220,7 @@ LLFolderView::LLFolderView(const Params& p) params.font(getLabelFontForStyle(LLFontGL::NORMAL)); params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN); params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); - params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe); + params.prevalidator(&LLTextValidate::validateASCIIPrintableNoPipe); params.commit_on_focus_lost(true); params.visible(false); mRenamer = LLUICtrlFactory::create<LLLineEditor> (params); diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 3bf77cdb1c..406cc36119 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -82,9 +82,9 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>( LLLineEditor::Params::Params() : max_length(""), - keystroke_callback("keystroke_callback"), - prevalidate_callback("prevalidate_callback"), - prevalidate_input_callback("prevalidate_input_callback"), + keystroke_callback("keystroke_callback"), + prevalidator("prevalidator"), + input_prevalidator("input_prevalidator"), background_image("background_image"), background_image_disabled("background_image_disabled"), background_image_focused("background_image_focused"), @@ -112,6 +112,8 @@ LLLineEditor::Params::Params() default_text("default_text") { changeDefault(mouse_opaque, true); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(input_prevalidator, "prevalidate_input_callback"); addSynonym(select_on_focus, "select_all_on_focus_received"); addSynonym(border, "border"); addSynonym(label, "watermark_text"); @@ -159,6 +161,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mUseBgColor(p.use_bg_color), mHaveHistory(FALSE), mReplaceNewlinesWithSpaces( TRUE ), + mPrevalidator(p.prevalidator()), + mInputPrevalidator(p.input_prevalidator()), mLabel(p.label), mCursorColor(p.cursor_color()), mBgColor(p.bg_color()), @@ -212,8 +216,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) } mSpellCheckTimer.reset(); - setPrevalidateInput(p.prevalidate_input_callback()); - setPrevalidate(p.prevalidate_callback()); + updateAllowingLanguageInput(); } LLLineEditor::~LLLineEditor() @@ -1210,11 +1213,12 @@ void LLLineEditor::cut() deleteSelection(); // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -1343,11 +1347,12 @@ void LLLineEditor::pasteHelper(bool is_primary) deselect(); // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -1590,19 +1595,27 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) deselect(); } - BOOL need_to_rollback = FALSE; + bool prevalidator_failed = false; // If read-only, don't allow changes - need_to_rollback |= (mReadOnly && (mText.getString() == rollback.getText())); + bool need_to_rollback = mReadOnly && (mText.getString() == rollback.getText()); // Validate new string and rollback the keystroke if needed. - need_to_rollback |= (mPrevalidateFunc && !mPrevalidateFunc(mText.getWString())); + if (!need_to_rollback && mPrevalidator) + { + prevalidator_failed = !mPrevalidator.validate(mText.getWString()); + need_to_rollback |= prevalidator_failed; + } if (need_to_rollback) { rollback.doRollback(this); LLUI::getInstance()->reportBadKeystroke(); + if (prevalidator_failed) + { + mPrevalidator.showLastErrorUsingTimeout(); + } } // Notify owner if requested @@ -1649,20 +1662,18 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) deselect(); - BOOL need_to_rollback = FALSE; - // Validate new string and rollback the keystroke if needed. - need_to_rollback |= ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - - if( need_to_rollback ) + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { rollback.doRollback( this ); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } // Notify owner if requested - if( !need_to_rollback && handled ) + if (!need_to_rollback && handled) { // HACK! The only usage of this callback doesn't do anything with the character. // We'll have to do something about this if something ever changes! - Doug @@ -1692,7 +1703,7 @@ void LLLineEditor::doDelete() deleteSelection(); } else if ( getCursor() < mText.length()) - { + { const LLWString& text_to_delete = mText.getWString().substr(getCursor(), 1); if (!prevalidateInput(text_to_delete)) @@ -1705,11 +1716,12 @@ void LLLineEditor::doDelete() } // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) { - rollback.doRollback( this ); + rollback.doRollback(this); LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); } else { @@ -2241,7 +2253,7 @@ void LLLineEditor::setFocus( BOOL new_state ) // fine on 1.15.0.2, since all prevalidate func reject any // non-ASCII characters. I'm not sure on future versions, // however. - getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL); + getWindow()->allowLanguageTextInput(this, !mPrevalidator); } } @@ -2260,26 +2272,21 @@ void LLLineEditor::setRect(const LLRect& rect) } } -void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidate(LLTextValidate::Validator validator) { - mPrevalidateFunc = func; + mPrevalidator = validator; updateAllowingLanguageInput(); } -void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidateInput(LLTextValidate::Validator validator) { - mPrevalidateInputFunc = func; + mInputPrevalidator = validator; updateAllowingLanguageInput(); } bool LLLineEditor::prevalidateInput(const LLWString& wstr) { - if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr)) - { - return false; - } - - return true; + return mInputPrevalidator.validate(wstr); } // static @@ -2421,7 +2428,7 @@ void LLLineEditor::updateAllowingLanguageInput() // test app, no window available return; } - if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) + if (hasFocus() && !mReadOnly && !mDrawAsterixes && !mPrevalidator) { window->allowLanguageTextInput(this, TRUE); } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 87afa9a1d5..15eb789897 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -76,8 +76,8 @@ public: Optional<MaxLength> max_length; Optional<keystroke_callback_t> keystroke_callback; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_input_callback; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator; Optional<LLViewBorder::Params> border; @@ -268,12 +268,12 @@ public: void setTextPadding(S32 left, S32 right); // Prevalidation controls which keystrokes can affect the editor - void setPrevalidate( LLTextValidate::validate_func_t func ); + void setPrevalidate(LLTextValidate::Validator validator); // This method sets callback that prevents from: // - deleting, selecting, typing, cutting, pasting characters that are not valid. // Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed // symbols, before existing text is modified, but setPrevalidate validates line after it was modified. - void setPrevalidateInput(LLTextValidate::validate_func_t func); + void setPrevalidateInput(LLTextValidate::Validator validator); static BOOL postvalidateFloat(const std::string &str); bool prevalidateInput(const LLWString& wstr); @@ -375,8 +375,8 @@ protected: std::list<std::pair<U32, U32> > mMisspellRanges; std::vector<std::string> mSuggestionList; - LLTextValidate::validate_func_t mPrevalidateFunc; - LLTextValidate::validate_func_t mPrevalidateInputFunc; + LLTextValidate::Validator mPrevalidator; + LLTextValidate::Validator mInputPrevalidator; LLFrameTimer mKeystrokeTimer; LLTimer mTripleClickTimer; diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index b3df7c154b..b651d85970 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -138,7 +138,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.font(p.font); params.max_length.bytes(MAX_STRING_LENGTH); params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit); - params.prevalidate_callback(&LLTextValidate::validateFloat); + params.prevalidator(&LLTextValidate::validateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index d65c220974..f18569d47f 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -47,9 +47,9 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id ) mLocale = locale_id; } -char LLResMgr::getDecimalPoint() const +char LLResMgr::getDecimalPoint() const { - char decimal = localeconv()->decimal_point[0]; + char decimal = localeconv()->decimal_point[0]; #if LL_DARWIN // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. @@ -62,9 +62,9 @@ char LLResMgr::getDecimalPoint() const return decimal; } -char LLResMgr::getThousandsSeparator() const +char LLResMgr::getThousandsSeparator() const { - char separator = localeconv()->thousands_sep[0]; + char separator = localeconv()->thousands_sep[0]; #if LL_DARWIN // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. @@ -79,7 +79,7 @@ char LLResMgr::getThousandsSeparator() const char LLResMgr::getMonetaryDecimalPoint() const { - char decimal = localeconv()->mon_decimal_point[0]; + char decimal = localeconv()->mon_decimal_point[0]; #if LL_DARWIN // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. @@ -92,9 +92,9 @@ char LLResMgr::getMonetaryDecimalPoint() const return decimal; } -char LLResMgr::getMonetaryThousandsSeparator() const +char LLResMgr::getMonetaryThousandsSeparator() const { - char separator = localeconv()->mon_thousands_sep[0]; + char separator = localeconv()->mon_thousands_sep[0]; #if LL_DARWIN // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index d80a434f22..e6cb739702 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -167,7 +167,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) } line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit); - line_p.prevalidate_callback(&LLTextValidate::validateFloat); + line_p.prevalidator(&LLTextValidate::validateFloat); mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index e9ddc6cf0b..875a5faa2b 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -232,17 +232,18 @@ private: /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() : default_text("default_text"), - prevalidate_callback("prevalidate_callback"), + prevalidator("prevalidator"), embedded_items("embedded_items", false), ignore_tab("ignore_tab", true), auto_indent("auto_indent", true), default_color("default_color"), - commit_on_focus_lost("commit_on_focus_lost", false), + commit_on_focus_lost("commit_on_focus_lost", false), show_context_menu("show_context_menu"), show_emoji_helper("show_emoji_helper"), enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(prevalidator, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : @@ -253,16 +254,17 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mLastCmd( NULL ), mDefaultColor( p.default_color() ), mAutoIndent(p.auto_indent), + mParseOnTheFly(false), mCommitOnFocusLost( p.commit_on_focus_lost), mAllowEmbeddedItems( p.embedded_items ), mMouseDownX(0), mMouseDownY(0), mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), + mPrevalidator(p.prevalidator()), mShowContextMenu(p.show_context_menu), mShowEmojiHelper(p.show_emoji_helper), mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), + mPassDelete(false), mKeepSelectionOnReturn(false) { mSourceID.generate(); @@ -278,7 +280,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : addChild( mBorder ); setText(p.default_text()); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) @@ -319,11 +321,13 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { // validate incoming text if necessary - if (mPrevalidateFunc) + if (mPrevalidator) { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) + if (!mPrevalidator.validate(utf8str)) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + // not valid text, nothing to do return; } @@ -332,9 +336,9 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param blockUndo(); deselect(); - mParseOnTheFly = FALSE; + mParseOnTheFly = false; LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; resetDirty(); } @@ -609,7 +613,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces ) // Disabling parsing on the fly to avoid updating text segments // until all indentation commands are executed. - mParseOnTheFly = FALSE; + mParseOnTheFly = false; // Find each start-of-line and indent it do @@ -636,7 +640,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces ) } while( cur < right ); - mParseOnTheFly = TRUE; + mParseOnTheFly = true; if( (right < getLength()) && (text[right] == '\n') ) { @@ -986,10 +990,12 @@ S32 LLTextEditor::execute( TextCmd* cmd ) mUndoStack.push_front(cmd); mLastCmd = cmd; - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay()); if (need_to_rollback) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + // get rid of this last command and clean up undo stack undo(); @@ -1125,16 +1131,15 @@ void LLTextEditor::removeChar() // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength) { - make_ui_sound("UISndBadKeystroke"); + LLUI::getInstance()->reportBadKeystroke(); return 0; } if (mLastCmd && mLastCmd->canExtend(pos)) { - S32 delta = 0; - if (mPrevalidateFunc) + if (mPrevalidator) { // get a copy of current text contents LLWString test_string(getViewModel()->getDisplay()); @@ -1142,28 +1147,31 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) // modify text contents as if this addChar succeeded llassert(pos <= (S32)test_string.size()); test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) + if (!mPrevalidator.validate(test_string)) { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); return 0; } } + + S32 delta = 0; mLastCmd->extendAndExecute(this, pos, wc, &delta); return delta; } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) + if (!getEnabled()) { return; } - if( hasSelection() ) + + if (hasSelection()) { deleteSelection(TRUE); } @@ -1508,7 +1516,13 @@ void LLTextEditor::pastePrimary() // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; + struct BoolReset + { + BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; } + ~BoolReset() { *mValuePtr = true; } + bool* mValuePtr; + } reset(mParseOnTheFly); + bool can_paste_it; if (is_primary) { @@ -1550,7 +1564,6 @@ void LLTextEditor::pasteHelper(bool is_primary) deselect(); onKeyStroke(); - mParseOnTheFly = TRUE; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 521405ec25..ded1444008 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -54,7 +54,7 @@ public: struct Params : public LLInitParam::Block<Params, LLTextBase::Params> { Optional<std::string> default_text; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; Optional<bool> embedded_items, ignore_tab, @@ -337,7 +337,7 @@ private: LLCoordGL mLastIMEPosition; // Last position of the IME editor keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + LLTextValidate::Validator mPrevalidator; LLHandle<LLContextMenu> mContextMenuHandle; }; // end class LLTextEditor diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index bfe0a5bb5d..9e27ed6232 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -27,330 +27,452 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #include "lltextvalidate.h" + +#include "llnotificationsutil.h" +#include "lltrans.h" + #include "llresmgr.h" // for LLLocale namespace LLTextValidate { - void ValidateTextNamedFuncs::declareValues() - { - declare("ascii", validateASCII); - declare("float", validateFloat); - declare("int", validateInt); - declare("positive_s32", validatePositiveS32); - declare("non_negative_s32", validateNonNegativeS32); - declare("alpha_num", validateAlphaNum); - declare("alpha_num_space", validateAlphaNumSpace); - declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); - declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); - declare("ascii_with_newline", validateASCIIWithNewLine); - } - - // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateFloat(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - if( 0 < len ) - { - // May be a comma or period, depending on the locale - llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint(); - - S32 i = 0; - - // First character can be a negative sign - if( '-' == trimmed[0] ) - { - i++; - } - - for( ; i < len; i++ ) - { - if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) ) - { - success = FALSE; - break; - } - } - } - - return success; - } - - // Limits what characters can be used to [1234567890-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateInt(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - if( 0 < len ) - { - S32 i = 0; - - // First character can be a negative sign - if( '-' == trimmed[0] ) - { - i++; - } - - for( ; i < len; i++ ) - { - if( !LLStringOps::isDigit( trimmed[i] ) ) - { - success = FALSE; - break; - } - } - } - - return success; - } - - bool validatePositiveS32(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) - { - if(('-' == trimmed[0]) || ('0' == trimmed[0])) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(trimmed[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val <= 0) - { - success = FALSE; - } - } - return success; - } - - bool validateNonNegativeS32(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) - { - if('-' == trimmed[0]) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(trimmed[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } - } - return success; - } - - bool validateNonNegativeS32NoSpace(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString test_str = str; - S32 len = test_str.length(); - bool success = TRUE; - if(0 < len) - { - if('-' == test_str[0]) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } - } - return success; - } - - bool validateAlphaNum(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - if( !LLStringOps::isAlnum((char)str[len]) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateAlphaNumSpace(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len]))) - { - rv = FALSE; - break; - } - } - return rv; - } - - // Used for most names of things stored on the server, due to old file-formats - // that used the pipe (|) for multiline text storage. Examples include - // inventory item names, parcel names, object names, etc. - bool validateASCIIPrintableNoPipe(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || wc == '|') - { - rv = FALSE; - break; - } - if(!(wc == ' ' - || LLStringOps::isAlnum((char)wc) - || LLStringOps::isPunct((char)wc) ) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - - // Used for avatar names - bool validateASCIIPrintableNoSpace(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || LLStringOps::isSpace(wc)) - { - rv = FALSE; - break; - } - if( !(LLStringOps::isAlnum((char)str[len]) || - LLStringOps::isPunct((char)str[len]) ) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateASCII(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - while(len--) - { - if (str[len] < 0x20 || str[len] > 0x7f) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateASCIINoLeadingSpace(const LLWString &str) - { - if (LLStringOps::isSpace(str[0])) - { - return FALSE; - } - return validateASCII(str); - } - - // Used for multiline text stored on the server. - // Example is landmark description in Places SP. - bool validateASCIIWithNewLine(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - while(len--) - { - if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f) - { - rv = FALSE; - break; - } - } - return rv; - } + +static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); } +static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); } + +static LLSD llsd(const std::string& str) { return LLSD(str); } +static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); } +template <class CHAR> +LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(1, ch)); } + +void ValidatorImpl::setLastErrorShowTime() +{ + mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime(); +} + +void Validator::showLastErrorUsingTimeout(U32 timeout) +{ + if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout) + { + mImpl->setLastErrorShowTime(); + std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues()); + LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason)); + } } + +// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorFloat : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + // May be a comma or period, depending on the locale + CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint(); + + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if ((decimal_point != ch) && !LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorFloatImpl; +Validator validateFloat(validatorFloatImpl); + +// Limits what characters can be used to [1234567890-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorInt : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorIntImpl; +Validator validateInt(validatorIntImpl); + +class ValidatorPositiveS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if (('-' == ch) || ('0' == ch)) + { + return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val <= 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorPositiveS32Impl; +Validator validatePositiveS32(validatorPositiveS32Impl); + +class ValidatorNonNegativeS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32Impl; +Validator validateNonNegativeS32(validatorNonNegativeS32Impl); + +class ValidatorNonNegativeS32NoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> test_str = str; + S32 len = test_str.length(); + if (0 < len) + { + CHAR ch = test_str.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = test_str[i]; + if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch)) + { + return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(test_str); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32NoSpaceImpl; +Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl); + +class ValidatorAlphaNum : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch)) + { + return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumImpl; +Validator validateAlphaNum(validatorAlphaNumImpl); + +class ValidatorAlphaNumSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch) && (' ' != ch)) + { + return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumSpaceImpl; +Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl); + +// Used for most names of things stored on the server, due to old file-formats +// that used the pipe (|) for multiline text storage. Examples include +// inventory item names, parcel names, object names, etc. +class ValidatorASCIIPrintableNoPipe : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f || ch == '|' || + (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoPipeImpl; +Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl); + +// Used for avatar names +class ValidatorASCIIPrintableNoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) || + (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoSpaceImpl; +Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl); + +class ValidatorASCII : public ValidatorImpl +{ +protected: + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f) + { + return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIImpl; +Validator validateASCII(validatorASCIIImpl); + +class ValidatorASCIINoLeadingSpace : public ValidatorASCII +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + if (LLStringOps::isSpace(str.front())) + { + return false; + } + + return ValidatorASCII::validate<CHAR>(str); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIINoLeadingSpaceImpl; +Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl); + +class ValidatorASCIIWithNewLine : public ValidatorImpl +{ + // Used for multiline text stored on the server. + // Example is landmark description in Places SP. + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if ((ch < 0x20 && ch != 0xA) || ch > 0x7f) + { + return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIWithNewLineImpl; +Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl); + +void Validators::declareValues() +{ + declare("ascii", validateASCII); + declare("float", validateFloat); + declare("int", validateInt); + declare("positive_s32", validatePositiveS32); + declare("non_negative_s32", validateNonNegativeS32); + declare("alpha_num", validateAlphaNum); + declare("alpha_num_space", validateAlphaNumSpace); + declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); + declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); + declare("ascii_with_newline", validateASCIIWithNewLine); +} + +} // namespace LLTextValidate diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index e2b6c313d6..2c2941de7f 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -34,27 +34,68 @@ namespace LLTextValidate { - typedef boost::function<BOOL (const LLWString &wstr)> validate_func_t; - - struct ValidateTextNamedFuncs - : public LLInitParam::TypeValuesHelper<validate_func_t, ValidateTextNamedFuncs> - { - static void declareValues(); - }; - - bool validateFloat(const LLWString &str ); - bool validateInt(const LLWString &str ); - bool validatePositiveS32(const LLWString &str); - bool validateNonNegativeS32(const LLWString &str); - bool validateNonNegativeS32NoSpace(const LLWString &str); - bool validateAlphaNum(const LLWString &str ); - bool validateAlphaNumSpace(const LLWString &str ); - bool validateASCIIPrintableNoPipe(const LLWString &str); - bool validateASCIIPrintableNoSpace(const LLWString &str); - bool validateASCII(const LLWString &str); - bool validateASCIINoLeadingSpace(const LLWString &str); - bool validateASCIIWithNewLine(const LLWString &str); -} + class ValidatorImpl + { + public: + ValidatorImpl() {} + virtual ~ValidatorImpl() {} + virtual bool validate(const std::string& str) = 0; + virtual bool validate(const LLWString& str) = 0; + + bool setError(std::string name, LLSD values = LLSD()) { return mLastErrorName = name, mLastErrorValues = values, false; } + bool resetError() { return mLastErrorName.clear(), mLastErrorValues.clear(), true; } + const std::string& getLastErrorName() const { return mLastErrorName; } + const LLSD& getLastErrorValues() const { return mLastErrorValues; } + + void setLastErrorShowTime(); + U32 getLastErrorShowTime() const { return mLastErrorShowTime; } + + protected: + std::string mLastErrorName; + LLSD mLastErrorValues; + U32 mLastErrorShowTime { 0 }; + }; + + class Validator + { + public: + Validator() : mImpl(nullptr) {} + Validator(ValidatorImpl& impl) : mImpl(&impl) {} + Validator(const Validator& validator) : mImpl(validator.mImpl) {} + Validator(const Validator* validator) : mImpl(validator->mImpl) {} + + bool validate(const std::string& str) const { return !mImpl || mImpl->validate(str); } + bool validate(const LLWString& str) const { return !mImpl || mImpl->validate(str); } + + operator bool() const { return mImpl; } + + static const U32 SHOW_LAST_ERROR_TIMEOUT_SEC = 30; + void showLastErrorUsingTimeout(U32 timeout = SHOW_LAST_ERROR_TIMEOUT_SEC); + + private: + ValidatorImpl* mImpl; + }; + + // Available validators + extern Validator validateFloat; + extern Validator validateInt; + extern Validator validatePositiveS32; + extern Validator validateNonNegativeS32; + extern Validator validateNonNegativeS32NoSpace; + extern Validator validateAlphaNum; + extern Validator validateAlphaNumSpace; + extern Validator validateASCIIPrintableNoPipe; + extern Validator validateASCIIPrintableNoSpace; + extern Validator validateASCII; + extern Validator validateASCIINoLeadingSpace; + extern Validator validateASCIIWithNewLine; + + // Add available validators to the internal map + struct Validators : public LLInitParam::TypeValuesHelper<Validator, Validators> + { + static void declareValues(); + }; +}; #endif diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp index 516057f8fd..564d0b6264 100644 --- a/indra/llui/lltimectrl.cpp +++ b/indra/llui/lltimectrl.cpp @@ -49,6 +49,36 @@ const U32 HOURS_MAX = 12; const U32 MINUTES_PER_HOUR = 60; const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR; +class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl +{ +public: + // virtual + bool validate(const std::string& str) override + { + std::string hours = LLTimeCtrl::getHoursString(str); + if (!LLTimeCtrl::isHoursStringValid(hours)) + return setError("ValidatorInvalidHours", LLSD().with("STR", hours)); + + std::string minutes = LLTimeCtrl::getMinutesString(str); + if (!LLTimeCtrl::isMinutesStringValid(minutes)) + return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes)); + + std::string ampm = LLTimeCtrl::getAMPMString(str); + if (!LLTimeCtrl::isPMAMStringValid(ampm)) + return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm)); + + return resetError(); + } + + // virtual + bool validate(const LLWString& wstr) override + { + std::string str = wstring_to_utf8str(wstr); + + return validate(str); + } +} validateTimeImpl; +LLTextValidate::Validator validateTime(validateTimeImpl); LLTimeCtrl::Params::Params() : label_width("label_width"), @@ -111,7 +141,7 @@ LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p) params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1)); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); - mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1)); + mEditor->setPrevalidate(validateTime); mEditor->setText(LLStringExplicit("12:00 AM")); addChild(mEditor); @@ -247,15 +277,6 @@ void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor) mTime = h24 * MINUTES_PER_HOUR + m; } -bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr) -{ - std::string str = wstring_to_utf8str(wstr); - - return isHoursStringValid(getHoursString(str)) && - isMinutesStringValid(getMinutesString(str)) && - isPMAMStringValid(getAMPMString(str)); -} - void LLTimeCtrl::increaseMinutes() { mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin); diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h index b5f268c76a..1c8ac78289 100644 --- a/indra/llui/lltimectrl.h +++ b/indra/llui/lltimectrl.h @@ -60,6 +60,18 @@ public: void setTime24(F32 time); // 0.0 - 23.98(3) + static std::string getHoursString(const std::string& str); + static std::string getMinutesString(const std::string& str); + static std::string getAMPMString(const std::string& str); + + static bool isHoursStringValid(const std::string& str); + static bool isMinutesStringValid(const std::string& str); + static bool isPMAMStringValid(const std::string& str); + + static U32 parseHours(const std::string& str); + static U32 parseMinutes(const std::string& str); + static bool parseAMPM(const std::string& str); + protected: LLTimeCtrl(const Params&); friend class LLUICtrlFactory; @@ -87,8 +99,6 @@ private: void onDownBtn(); void onTextEntry(LLLineEditor* line_editor); - bool isTimeStringValid(const LLWString& wstr); - void increaseMinutes(); void increaseHours(); @@ -102,18 +112,6 @@ private: EEditingPart getEditingPart(); - static std::string getHoursString(const std::string& str); - static std::string getMinutesString(const std::string& str); - static std::string getAMPMString(const std::string& str); - - static bool isHoursStringValid(const std::string& str); - static bool isMinutesStringValid(const std::string& str); - static bool isPMAMStringValid(const std::string& str); - - static U32 parseHours(const std::string& str); - static U32 parseMinutes(const std::string& str); - static bool parseAMPM(const std::string& str); - class LLTextBox* mLabelBox; class LLLineEditor* mEditor; |