803 lines
22 KiB
C++
803 lines
22 KiB
C++
/**
|
|
* @file llautoreplace.cpp
|
|
* @brief Auto Replace Manager
|
|
*
|
|
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2012, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
#include "llautoreplace.h"
|
|
#include "llsdserialize.h"
|
|
#include "llboost.h"
|
|
#include "llcontrol.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llnotificationsutil.h"
|
|
|
|
const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml";
|
|
|
|
void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text)
|
|
{
|
|
// make sure these returned values are cleared in case there is no replacement
|
|
replacement_start = 0;
|
|
replacement_length = 0;
|
|
replacement_string.clear();
|
|
|
|
static LLCachedControl<bool> perform_autoreplace(gSavedSettings, "AutoReplace", 0);
|
|
if (perform_autoreplace)
|
|
{
|
|
S32 word_end = cursor_pos - 1;
|
|
|
|
bool at_space = (input_text[word_end] == ' ');
|
|
bool have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
|
|
|
if (at_space || have_word)
|
|
{
|
|
if (at_space && word_end > 0)
|
|
{
|
|
// find out if this space immediately follows a word
|
|
word_end--;
|
|
have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
|
}
|
|
if (have_word)
|
|
{
|
|
// word_end points to the end of a word, now find the start of the word
|
|
std::string word;
|
|
S32 word_start = word_end;
|
|
for (S32 back_one = word_start - 1;
|
|
back_one >= 0 && LLWStringUtil::isPartOfWord(input_text[back_one]);
|
|
back_one--
|
|
)
|
|
{
|
|
word_start--; // walk word_start back to the beginning of the word
|
|
}
|
|
LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL;
|
|
std::string str_text = std::string(input_text.begin(), input_text.end());
|
|
std::string last_word = str_text.substr(word_start, word_end - word_start + 1);
|
|
std::string replacement_word(mSettings.replaceWord(last_word));
|
|
|
|
if (replacement_word != last_word)
|
|
{
|
|
// The last word is one for which we have a replacement
|
|
if (at_space)
|
|
{
|
|
// return the replacement string
|
|
replacement_start = word_start;
|
|
replacement_length = last_word.length();
|
|
replacement_string = utf8str_to_wstring(replacement_word);
|
|
LLWString old_string = utf8str_to_wstring(last_word);
|
|
S32 size_change = replacement_string.size() - old_string.size();
|
|
cursor_pos += size_change;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string LLAutoReplace::getUserSettingsFileName()
|
|
{
|
|
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
|
|
|
|
if (!path.empty())
|
|
{
|
|
path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, SETTINGS_FILE_NAME);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
std::string LLAutoReplace::getAppSettingsFileName()
|
|
{
|
|
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "");
|
|
|
|
if (!path.empty())
|
|
{
|
|
path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, SETTINGS_FILE_NAME);
|
|
}
|
|
else
|
|
{
|
|
LL_ERRS("AutoReplace") << "Failed to get app settings directory name" << LL_ENDL;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
LLAutoReplaceSettings LLAutoReplace::getSettings()
|
|
{
|
|
return mSettings;
|
|
}
|
|
|
|
void LLAutoReplace::setSettings(const LLAutoReplaceSettings& newSettings)
|
|
{
|
|
mSettings.set(newSettings);
|
|
/// Make the newSettings active and write them to user storage
|
|
saveToUserSettings();
|
|
}
|
|
|
|
LLAutoReplace::LLAutoReplace()
|
|
{
|
|
}
|
|
|
|
void LLAutoReplace::initSingleton()
|
|
{
|
|
loadFromSettings();
|
|
}
|
|
|
|
void LLAutoReplace::loadFromSettings()
|
|
{
|
|
std::string filename=getUserSettingsFileName();
|
|
if (filename.empty())
|
|
{
|
|
LL_INFOS("AutoReplace") << "no valid user settings directory." << LL_ENDL;
|
|
}
|
|
if(gDirUtilp->fileExists(filename))
|
|
{
|
|
LLSD userSettings;
|
|
llifstream file;
|
|
file.open(filename.c_str());
|
|
if (file.is_open())
|
|
{
|
|
LLSDSerialize::fromXML(userSettings, file);
|
|
}
|
|
file.close();
|
|
if ( mSettings.setFromLLSD(userSettings) )
|
|
{
|
|
LL_INFOS("AutoReplace") << "settings loaded from '" << filename << "'" << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "invalid settings found in '" << filename << "'" << LL_ENDL;
|
|
}
|
|
}
|
|
else // no user settings found, try application settings
|
|
{
|
|
std::string defaultName = getAppSettingsFileName();
|
|
LL_INFOS("AutoReplace") << " user settings file '" << filename << "' not found"<< LL_ENDL;
|
|
|
|
bool gotSettings = false;
|
|
if(gDirUtilp->fileExists(defaultName))
|
|
{
|
|
LLSD appDefault;
|
|
llifstream file;
|
|
file.open(defaultName.c_str());
|
|
if (file.is_open())
|
|
{
|
|
LLSDSerialize::fromXMLDocument(appDefault, file);
|
|
}
|
|
file.close();
|
|
|
|
if ( mSettings.setFromLLSD(appDefault) )
|
|
{
|
|
LL_INFOS("AutoReplace") << "settings loaded from '" << defaultName.c_str() << "'" << LL_ENDL;
|
|
gotSettings = true;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "invalid settings found in '" << defaultName.c_str() << "'" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
if ( ! gotSettings )
|
|
{
|
|
if (mSettings.setFromLLSD(mSettings.getExampleLLSD()))
|
|
{
|
|
LL_WARNS("AutoReplace") << "no settings found; loaded example." << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "no settings found and example invalid!" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLAutoReplace::saveToUserSettings()
|
|
{
|
|
std::string filename=getUserSettingsFileName();
|
|
llofstream file;
|
|
file.open(filename.c_str());
|
|
LLSDSerialize::toPrettyXML(mSettings.asLLSD(), file);
|
|
file.close();
|
|
LL_INFOS("AutoReplace") << "settings saved to '" << filename << "'" << LL_ENDL;
|
|
}
|
|
|
|
// ================================================================
|
|
// LLAutoReplaceSettings
|
|
// ================================================================
|
|
|
|
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_NAME = "name"; ///< key for looking up list names
|
|
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_REPLACEMENTS = "replacements"; ///< key for looking up replacement map
|
|
|
|
LLAutoReplaceSettings::LLAutoReplaceSettings()
|
|
{
|
|
}
|
|
|
|
LLAutoReplaceSettings::LLAutoReplaceSettings(const LLAutoReplaceSettings& settings)
|
|
{
|
|
// copy all values through fundamental type intermediates for thread safety
|
|
mLists = LLSD::emptyArray();
|
|
|
|
for ( LLSD::array_const_iterator list = settings.mLists.beginArray(), listEnd = settings.mLists.endArray();
|
|
list != listEnd;
|
|
list++
|
|
)
|
|
{
|
|
if ( (*list).isMap() ) // can fail due to LLSD-30: ignore it
|
|
{
|
|
LLSD listMap = LLSD::emptyMap();
|
|
std::string listName = (*list)[AUTOREPLACE_LIST_NAME];
|
|
listMap[AUTOREPLACE_LIST_NAME] = listName;
|
|
listMap[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
|
|
|
for ( LLSD::map_const_iterator
|
|
entry = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
|
entriesEnd = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
|
entry != entriesEnd;
|
|
entry++
|
|
)
|
|
{
|
|
std::string keyword = entry->first;
|
|
std::string replacement = entry->second.asString();
|
|
listMap[AUTOREPLACE_LIST_REPLACEMENTS].insert(keyword, LLSD(replacement));
|
|
}
|
|
|
|
mLists.append(listMap);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLAutoReplaceSettings::set(const LLAutoReplaceSettings& newSettings)
|
|
{
|
|
mLists = newSettings.mLists;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::setFromLLSD(const LLSD& settingsFromLLSD)
|
|
{
|
|
bool settingsValid = true;
|
|
|
|
if ( settingsFromLLSD.isArray() )
|
|
{
|
|
for ( LLSD::array_const_iterator
|
|
list = settingsFromLLSD.beginArray(),
|
|
listEnd = settingsFromLLSD.endArray();
|
|
settingsValid && list != listEnd;
|
|
list++
|
|
)
|
|
{
|
|
if ( (*list).isDefined() ) // can be undef due to LLSD-30: ignore it
|
|
{
|
|
settingsValid = listIsValid(*list);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
settingsValid = false;
|
|
LL_WARNS("AutoReplace") << "settings are not an array" << LL_ENDL;
|
|
}
|
|
|
|
if ( settingsValid )
|
|
{
|
|
mLists = settingsFromLLSD;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "invalid settings discarded; using hard coded example" << LL_ENDL;
|
|
}
|
|
|
|
return settingsValid;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::listNameMatches( const LLSD& list, const std::string name )
|
|
{
|
|
return list.isMap()
|
|
&& list.has(AUTOREPLACE_LIST_NAME)
|
|
&& list[AUTOREPLACE_LIST_NAME].asString() == name;
|
|
}
|
|
|
|
const LLSD* LLAutoReplaceSettings::getListEntries(std::string listName)
|
|
{
|
|
const LLSD* returnedEntries = NULL;
|
|
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
|
returnedEntries == NULL && list != endList;
|
|
list++
|
|
)
|
|
{
|
|
const LLSD& thisList = *list;
|
|
if ( listNameMatches(thisList, listName) )
|
|
{
|
|
returnedEntries = &thisList[AUTOREPLACE_LIST_REPLACEMENTS];
|
|
}
|
|
}
|
|
return returnedEntries;
|
|
}
|
|
|
|
std::string LLAutoReplaceSettings::replacementFor(std::string keyword, std::string listName)
|
|
{
|
|
std::string replacement;
|
|
bool foundList = false;
|
|
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
|
! foundList && list != endList;
|
|
list++
|
|
)
|
|
{
|
|
const LLSD& thisList = *list;
|
|
if ( listNameMatches(thisList, listName) )
|
|
{
|
|
foundList = true; // whether there is a replacement or not, we're done
|
|
if ( thisList.isMap()
|
|
&& thisList.has(AUTOREPLACE_LIST_REPLACEMENTS)
|
|
&& thisList[AUTOREPLACE_LIST_REPLACEMENTS].has(keyword)
|
|
)
|
|
{
|
|
replacement = thisList[AUTOREPLACE_LIST_REPLACEMENTS][keyword].asString();
|
|
LL_DEBUGS("AutoReplace")<<"'"<<keyword<<"' -> '"<<replacement<<"'"<<LL_ENDL;
|
|
}
|
|
}
|
|
if (!foundList)
|
|
{
|
|
LL_WARNS("AutoReplace")<<"failed to find list '"<<listName<<"'"<<LL_ENDL;
|
|
}
|
|
}
|
|
if (replacement.empty())
|
|
{
|
|
LL_WARNS("AutoReplace")<<"failed to find '"<<keyword<<"'"<<LL_ENDL;
|
|
}
|
|
return replacement;
|
|
}
|
|
|
|
LLSD LLAutoReplaceSettings::getListNames()
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"====="<<LL_ENDL;
|
|
LLSD toReturn = LLSD::emptyArray();
|
|
S32 counter=0;
|
|
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
|
list != endList;
|
|
list++
|
|
)
|
|
{
|
|
const LLSD& thisList = *list;
|
|
if ( thisList.isMap() )
|
|
{
|
|
if ( thisList.has(AUTOREPLACE_LIST_NAME) )
|
|
{
|
|
std::string name = thisList[AUTOREPLACE_LIST_NAME].asString();
|
|
LL_DEBUGS("AutoReplace")<<counter<<" '"<<name<<"'"<<LL_ENDL;
|
|
toReturn.append(LLSD(name));
|
|
}
|
|
else
|
|
{
|
|
LL_ERRS("AutoReplace") <<counter<<" ! MISSING "<<AUTOREPLACE_LIST_NAME<< LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace")<<counter<<" ! not a map: "/*<<LLSD::typeString(thisList.type())*/<< LL_ENDL;
|
|
}
|
|
counter++;
|
|
}
|
|
LL_DEBUGS("AutoReplace")<<"^^^^^^"<<LL_ENDL;
|
|
return toReturn;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::listIsValid(const LLSD& list)
|
|
{
|
|
bool listValid = true;
|
|
if ( ! list.isMap() )
|
|
{
|
|
listValid = false;
|
|
LL_WARNS("AutoReplace") << "list is not a map" << LL_ENDL;
|
|
}
|
|
else if ( ! list.has(AUTOREPLACE_LIST_NAME)
|
|
|| ! list[AUTOREPLACE_LIST_NAME].isString()
|
|
|| list[AUTOREPLACE_LIST_NAME].asString().empty()
|
|
)
|
|
{
|
|
listValid = false;
|
|
LL_WARNS("AutoReplace")
|
|
<< "list found without " << AUTOREPLACE_LIST_NAME
|
|
<< " (or it is empty)"
|
|
<< LL_ENDL;
|
|
}
|
|
else if ( ! list.has(AUTOREPLACE_LIST_REPLACEMENTS) || ! list[AUTOREPLACE_LIST_REPLACEMENTS].isMap() )
|
|
{
|
|
listValid = false;
|
|
LL_WARNS("AutoReplace") << "list '" << list[AUTOREPLACE_LIST_NAME].asString() << "' without " << AUTOREPLACE_LIST_REPLACEMENTS << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
for ( LLSD::map_const_iterator
|
|
entry = list[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
|
entriesEnd = list[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
|
listValid && entry != entriesEnd;
|
|
entry++
|
|
)
|
|
{
|
|
if ( ! entry->second.isString() )
|
|
{
|
|
listValid = false;
|
|
LL_WARNS("AutoReplace")
|
|
<< "non-string replacement value found in list '"
|
|
<< list[AUTOREPLACE_LIST_NAME].asString() << "'"
|
|
<< LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return listValid;
|
|
}
|
|
|
|
const LLSD* LLAutoReplaceSettings::exportList(std::string listName)
|
|
{
|
|
const LLSD* exportedList = NULL;
|
|
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
|
exportedList == NULL && list != listEnd;
|
|
list++
|
|
)
|
|
{
|
|
if ( listNameMatches(*list, listName) )
|
|
{
|
|
const LLSD& namedList = (*list);
|
|
exportedList = &namedList;
|
|
}
|
|
}
|
|
return exportedList;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::listNameIsUnique(const LLSD& newList)
|
|
{
|
|
bool nameIsUnique = true;
|
|
// this must always be called with a valid list, so it is safe to assume it has a name
|
|
std::string newListName = newList[AUTOREPLACE_LIST_NAME].asString();
|
|
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
|
nameIsUnique && list != listEnd;
|
|
list++
|
|
)
|
|
{
|
|
if ( listNameMatches(*list, newListName) )
|
|
{
|
|
LL_WARNS("AutoReplace")<<"duplicate list name '"<<newListName<<"'"<<LL_ENDL;
|
|
nameIsUnique = false;
|
|
}
|
|
}
|
|
return nameIsUnique;
|
|
}
|
|
|
|
/* static */
|
|
void LLAutoReplaceSettings::createEmptyList(LLSD& emptyList)
|
|
{
|
|
emptyList = LLSD::emptyMap();
|
|
emptyList[AUTOREPLACE_LIST_NAME] = "Empty";
|
|
emptyList[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
|
}
|
|
|
|
/* static */
|
|
void LLAutoReplaceSettings::setListName(LLSD& list, const std::string& newName)
|
|
{
|
|
list[AUTOREPLACE_LIST_NAME] = newName;
|
|
}
|
|
|
|
/* static */
|
|
std::string LLAutoReplaceSettings::getListName(LLSD& list)
|
|
{
|
|
std::string name;
|
|
if ( list.isMap() && list.has(AUTOREPLACE_LIST_NAME) && list[AUTOREPLACE_LIST_NAME].isString() )
|
|
{
|
|
name = list[AUTOREPLACE_LIST_NAME].asString();
|
|
}
|
|
return name;
|
|
}
|
|
|
|
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::addList(const LLSD& newList)
|
|
{
|
|
AddListResult result;
|
|
if ( listIsValid( newList ) )
|
|
{
|
|
if ( listNameIsUnique( newList ) )
|
|
{
|
|
mLists.append(newList);
|
|
result = AddListOk;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempt to add duplicate name" << LL_ENDL;
|
|
result = AddListDuplicateName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
|
result = AddListInvalidList;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::replaceList(const LLSD& newList)
|
|
{
|
|
AddListResult result = AddListInvalidList;
|
|
if ( listIsValid( newList ) )
|
|
{
|
|
std::string listName = newList[AUTOREPLACE_LIST_NAME].asString();
|
|
bool listFound = false;
|
|
S32 search_index;
|
|
LLSD targetList;
|
|
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
|
for ( search_index = 0, targetList = mLists[0];
|
|
!listFound && search_index < mLists.size();
|
|
search_index += 1, targetList = mLists[search_index]
|
|
)
|
|
{
|
|
if ( targetList.isMap() )
|
|
{
|
|
if ( listNameMatches( targetList, listName) )
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"list to replace found at "<<search_index<<LL_ENDL;
|
|
mLists.erase(search_index);
|
|
mLists.insert(search_index, newList);
|
|
listFound = true;
|
|
result = AddListOk;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! listFound )
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempt to replace unconfigured list" << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::removeReplacementList(std::string listName)
|
|
{
|
|
bool found = false;
|
|
for( S32 index = 0; !found && mLists[index].isDefined(); index++ )
|
|
{
|
|
if( listNameMatches(mLists.get(index), listName) )
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"list '"<<listName<<"'"<<LL_ENDL;
|
|
mLists.erase(index);
|
|
found = true;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/// Move the named list up in the priority order
|
|
bool LLAutoReplaceSettings::increaseListPriority(std::string listName)
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
|
bool found = false;
|
|
S32 search_index, previous_index;
|
|
LLSD targetList;
|
|
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
|
previous_index = -1;
|
|
for ( search_index = 0, targetList = mLists[0];
|
|
!found && search_index < mLists.size();
|
|
search_index += 1, targetList = mLists[search_index]
|
|
)
|
|
{
|
|
if ( targetList.isMap() )
|
|
{
|
|
if ( listNameMatches( targetList, listName) )
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"found at "<<search_index<<", previous is "<<previous_index<<LL_ENDL;
|
|
found = true;
|
|
if (previous_index >= 0)
|
|
{
|
|
LL_DEBUGS("AutoReplace") << "erase "<<search_index<<LL_ENDL;
|
|
mLists.erase(search_index);
|
|
LL_DEBUGS("AutoReplace") << "insert at "<<previous_index<<LL_ENDL;
|
|
mLists.insert(previous_index, targetList);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempted to move top list up" << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
previous_index = search_index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//LL_DEBUGS("AutoReplace") << search_index<<" is "<<LLSD::typeString(targetList.type())<<LL_ENDL;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/// Move the named list down in the priority order
|
|
bool LLAutoReplaceSettings::decreaseListPriority(std::string listName)
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
|
S32 found_index = -1;
|
|
S32 search_index;
|
|
for ( search_index = 0;
|
|
found_index == -1 && search_index < mLists.size();
|
|
search_index++
|
|
)
|
|
{
|
|
if ( listNameMatches( mLists[search_index], listName) )
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"found at index "<<search_index<<LL_ENDL;
|
|
found_index = search_index;
|
|
}
|
|
}
|
|
if (found_index != -1)
|
|
{
|
|
S32 next_index;
|
|
for ( next_index = found_index+1;
|
|
next_index < mLists.size() && ! mLists[next_index].isMap();
|
|
next_index++
|
|
)
|
|
{
|
|
// skipping over any undefined slots (see LLSD-30)
|
|
LL_WARNS("AutoReplace")<<next_index<<" ! not a map: "/*<<LLSD::typeString(mLists[next_index].type())*/<< LL_ENDL;
|
|
}
|
|
if ( next_index < mLists.size() )
|
|
{
|
|
LLSD next_list = mLists[next_index];
|
|
LL_DEBUGS("AutoReplace") << "erase "<<next_index<<LL_ENDL;
|
|
mLists.erase(next_index);
|
|
LL_DEBUGS("AutoReplace") << "insert at "<<found_index<<LL_ENDL;
|
|
mLists.insert(found_index, next_list);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "attempted to move bottom list down" << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "not found" << LL_ENDL;
|
|
}
|
|
return (found_index != -1);
|
|
}
|
|
|
|
|
|
std::string LLAutoReplaceSettings::replaceWord(const std::string currentWord)
|
|
{
|
|
std::string returnedWord = currentWord; // in case no replacement is found
|
|
static LLCachedControl<bool> autoreplace_enabled(gSavedSettings, "AutoReplace", false);
|
|
if ( autoreplace_enabled )
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<"checking '"<<currentWord<<"'"<< LL_ENDL;
|
|
//loop through lists in order
|
|
bool found = false;
|
|
for( LLSD::array_const_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
|
! found && list != endLists;
|
|
list++
|
|
)
|
|
{
|
|
const LLSD& checkList = *list;
|
|
const LLSD& replacements = checkList[AUTOREPLACE_LIST_REPLACEMENTS];
|
|
|
|
if ( replacements.has(currentWord) )
|
|
{
|
|
found = true;
|
|
LL_DEBUGS("AutoReplace")
|
|
<< " found in list '" << checkList[AUTOREPLACE_LIST_NAME].asString()
|
|
<< " => '" << replacements[currentWord].asString() << "'"
|
|
<< LL_ENDL;
|
|
returnedWord = replacements[currentWord].asString();
|
|
}
|
|
}
|
|
}
|
|
return returnedWord;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::addEntryToList(LLWString keyword, LLWString replacement, std::string listName)
|
|
{
|
|
bool added = false;
|
|
|
|
if ( ! keyword.empty() && ! replacement.empty() )
|
|
{
|
|
bool isOneWord = true;
|
|
for (size_t character = 0; isOneWord && character < keyword.size(); character++ )
|
|
{
|
|
if ( ! LLWStringUtil::isPartOfWord(keyword[character]) )
|
|
{
|
|
LL_WARNS("AutoReplace") << "keyword '" << wstring_to_utf8str(keyword) << "' not a single word (len "<<keyword.size()<<" '"<<character<<"')" << LL_ENDL;
|
|
isOneWord = false;
|
|
}
|
|
}
|
|
|
|
if ( isOneWord )
|
|
{
|
|
bool listFound = false;
|
|
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
|
! listFound && list != endLists;
|
|
list++
|
|
)
|
|
{
|
|
if ( listNameMatches(*list, listName) )
|
|
{
|
|
listFound = true;
|
|
(*list)[AUTOREPLACE_LIST_REPLACEMENTS][wstring_to_utf8str(keyword)]=wstring_to_utf8str(replacement);
|
|
}
|
|
}
|
|
if (listFound)
|
|
{
|
|
added = true;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return added;
|
|
}
|
|
|
|
bool LLAutoReplaceSettings::removeEntryFromList(std::string keyword, std::string listName)
|
|
{
|
|
bool found = false;
|
|
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
|
! found && list != endLists;
|
|
list++
|
|
)
|
|
{
|
|
if ( listNameMatches(*list, listName) )
|
|
{
|
|
found = true;
|
|
(*list)[AUTOREPLACE_LIST_REPLACEMENTS].erase(keyword);
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
LLSD LLAutoReplaceSettings::getExampleLLSD()
|
|
{
|
|
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
|
LLSD example = LLSD::emptyArray();
|
|
|
|
example[0] = LLSD::emptyMap();
|
|
example[0][AUTOREPLACE_LIST_NAME] = "Example List 1";
|
|
example[0][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
|
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword1"] = "replacement string 1";
|
|
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword2"] = "replacement string 2";
|
|
|
|
example[1] = LLSD::emptyMap();
|
|
example[1][AUTOREPLACE_LIST_NAME] = "Example List 2";
|
|
example[1][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
|
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake1"] = "correction 1";
|
|
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake2"] = "correction 2";
|
|
|
|
return example;
|
|
}
|
|
|
|
const LLSD& LLAutoReplaceSettings::asLLSD()
|
|
{
|
|
return mLists;
|
|
}
|
|
|
|
LLAutoReplaceSettings::~LLAutoReplaceSettings()
|
|
{
|
|
}
|