summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2024-03-12 18:30:33 +0100
committerGuru <alexandrgproductengine@lindenlab.com>2024-03-18 21:19:57 +0100
commit15734c19783fc5fc38e5c1cba485d756285161e0 (patch)
tree00f2c0586781b2abe32baa12ee2bb283b2839fef /indra/llui
parentb40ff113c50afc1e012183928e94b2c86252a61f (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.cpp2
-rw-r--r--indra/llui/lllineeditor.cpp75
-rw-r--r--indra/llui/lllineeditor.h12
-rw-r--r--indra/llui/llmultisliderctrl.cpp2
-rw-r--r--indra/llui/llresmgr.cpp14
-rw-r--r--indra/llui/llsliderctrl.cpp2
-rw-r--r--indra/llui/lltexteditor.cpp69
-rw-r--r--indra/llui/lltexteditor.h4
-rw-r--r--indra/llui/lltextvalidate.cpp764
-rw-r--r--indra/llui/lltextvalidate.h83
-rw-r--r--indra/llui/lltimectrl.cpp41
-rw-r--r--indra/llui/lltimectrl.h26
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;