summaryrefslogtreecommitdiff
path: root/indra/newview/llautocorrect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llautocorrect.cpp')
-rw-r--r--indra/newview/llautocorrect.cpp456
1 files changed, 456 insertions, 0 deletions
diff --git a/indra/newview/llautocorrect.cpp b/indra/newview/llautocorrect.cpp
new file mode 100644
index 0000000000..d1aa2384b7
--- /dev/null
+++ b/indra/newview/llautocorrect.cpp
@@ -0,0 +1,456 @@
+/**
+ * @file llautocorrect.cpp
+ * @brief Auto Correct Manager
+ * @copyright Copyright (c) 2011 LordGregGreg Back
+ *
+ * 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
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llautocorrect.h"
+#include "llsdserialize.h"
+#include "llboost.h"
+#include "llcontrol.h"
+#include "llviewercontrol.h"
+#include "llnotificationsutil.h"
+
+AutoCorrect* AutoCorrect::sInstance;
+
+AutoCorrect::AutoCorrect()
+{
+ sInstance = this;
+ sInstance->loadFromDisk();
+}
+
+AutoCorrect::~AutoCorrect()
+{
+ sInstance = NULL;
+}
+
+void AutoCorrect::autocorrectCallback(LLUIString& inputText, S32& cursorPos)
+{
+ static LLCachedControl<bool> doAnything(gSavedSettings, "EnableAutoCorrect");
+ if(doAnything)
+ {
+ S32 wordStart = 0;
+ S32 wordEnd = cursorPos-1;
+
+ if(wordEnd < 1)
+ return;
+
+ LLWString text = inputText.getWString();
+
+ if(text.size()<1)
+ return;
+
+ if(LLWStringUtil::isPartOfWord(text[wordEnd]))
+ return;//we only check on word breaks
+
+ wordEnd--;
+
+ if(LLWStringUtil::isPartOfWord(text[wordEnd]))
+ {
+ while ((wordEnd > 0) && (' ' != text[wordEnd-1]))
+ {
+ wordEnd--;
+ }
+
+ wordStart=wordEnd;
+
+ while ((wordEnd < (S32)text.length()) && (' ' != text[wordEnd]))
+ {
+ wordEnd++;
+ }
+
+ std::string strLastWord = std::string(text.begin(), text.end());
+ std::string lastTypedWord = strLastWord.substr(wordStart, wordEnd-wordStart);
+ std::string correctedWord(replaceWord(lastTypedWord));
+
+ if(correctedWord != lastTypedWord)
+ {
+ LLWString strNew = utf8str_to_wstring(correctedWord);
+ LLWString strOld = utf8str_to_wstring(lastTypedWord);
+ int nDiff = strNew.size() - strOld.size();
+
+ //int wordStart = regText.find(lastTypedWord);
+ text.replace(wordStart,lastTypedWord.length(),strNew);
+ inputText = wstring_to_utf8str(text);
+ cursorPos+=nDiff;
+ }
+ }
+ }
+}
+
+AutoCorrect* AutoCorrect::getInstance()
+{
+ if(sInstance)return sInstance;
+ else
+ {
+ sInstance = new AutoCorrect();
+ return sInstance;
+ }
+}
+void AutoCorrect::save()
+{
+ saveToDisk(mAutoCorrects);
+}
+std::string AutoCorrect::getFileName()
+{
+ std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
+
+ if (!path.empty())
+ {
+ path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings_autocorrect.xml");
+ }
+ return path;
+}
+std::string AutoCorrect::getDefaultFileName()
+{
+ std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "");
+
+ if (!path.empty())
+ {
+ path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_autocorrect.xml");
+ }
+ return path;
+}
+LLSD AutoCorrect::exportList(std::string listName)
+{
+ LLSD toReturn;
+ if(mAutoCorrects.has(listName))
+ {
+ toReturn["listName"]=listName;
+ toReturn["data"]=mAutoCorrects[listName]["data"];
+ toReturn["author"]=mAutoCorrects[listName]["author"];
+ toReturn["wordStyle"]=mAutoCorrects[listName]["wordStyle"];
+ toReturn["priority"]=mAutoCorrects[listName]["priority"];
+ }
+ return toReturn;
+}
+BOOL AutoCorrect::addCorrectionList(LLSD newList)
+{
+ if(newList.has("listName"))
+ {
+ std::string name = newList["listName"];
+ //if(!mAutoCorrects.has(name)){
+ LLSD newPart;
+ newPart["data"]=newList["data"];
+ newPart["enabled"]=TRUE;
+ newPart["announce"]=FALSE;
+ newPart["author"]=newList["author"];
+ newPart["wordStyle"]=newList["wordStyle"];
+ newPart["priority"]=newList["priority"].asInteger();
+ llinfos << "adding new list with settings priority "<<newPart["priority"].asInteger() <<llendl;
+ mAutoCorrects[name]=newPart;
+
+ return TRUE;
+
+ }
+ return FALSE;
+}
+BOOL AutoCorrect::removeCorrectionList(std::string listName)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects.erase(listName);
+ return TRUE;
+ }
+ return FALSE;
+}
+BOOL AutoCorrect::setListEnabled(std::string listName, BOOL enabled)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects[listName]["enabled"]=enabled;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+BOOL AutoCorrect::setListAnnounceeState(std::string listName, BOOL announce)
+{
+
+
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects[listName]["announce"]=announce;
+ return TRUE;
+ }
+ return FALSE;
+}
+BOOL AutoCorrect::setListStyle(std::string listName, BOOL announce)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects[listName]["wordStyle"]=announce;
+ return TRUE;
+ }
+ return FALSE;
+}
+BOOL AutoCorrect::setListPriority(std::string listName, int priority)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects[listName]["priority"]=priority;
+ return TRUE;
+ }
+ return FALSE;
+}
+LLSD AutoCorrect::getAutoCorrects()
+{
+ //loadFromDisk();
+ return mAutoCorrects;
+}
+void AutoCorrect::loadFromDisk()
+{
+ std::string filename=getFileName();
+ if (filename.empty())
+ {
+ llinfos << "no valid user directory." << llendl;
+ }
+ if(!gDirUtilp->fileExists(filename))
+ {
+ std::string defaultName = getDefaultFileName();
+ llinfos << " user settings file doesnt exist, going to try and read default one from "<<defaultName.c_str()<< llendl;
+
+ if(gDirUtilp->fileExists(defaultName))
+ {
+ LLSD blankllsd;
+ llifstream file;
+ file.open(defaultName.c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::fromXMLDocument(blankllsd, file);
+ }
+ file.close();
+ saveToDisk(blankllsd);
+ }else
+ saveToDisk(getExampleLLSD());
+ }
+ else
+ {
+ llifstream file;
+ file.open(filename.c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::fromXML(mAutoCorrects, file);
+ }
+ file.close();
+ }
+}
+void AutoCorrect::saveToDisk(LLSD newSettings)
+{
+ mAutoCorrects=newSettings;
+ std::string filename=getFileName();
+ llofstream file;
+ file.open(filename.c_str());
+ LLSDSerialize::toPrettyXML(mAutoCorrects, file);
+ file.close();
+}
+void AutoCorrect::runTest()
+{
+ std::string startS("He just abandonned all his abilties");
+ std::string endS = replaceWords(startS);
+ llinfos << "!!! Test of autoreplace; start with "<<startS.c_str() << " end with " << endS.c_str()<<llendl;
+
+
+}
+BOOL AutoCorrect::saveListToDisk(std::string listName, std::string fileName)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ llofstream file;
+ file.open(fileName.c_str());
+ LLSDSerialize::toPrettyXML(exportList(listName), file);
+ file.close();
+ return TRUE;
+ }
+ return FALSE;
+}
+LLSD AutoCorrect::getAutoCorrectEntries(std::string listName)
+{
+ LLSD toReturn;
+ if(mAutoCorrects.has(listName))
+ {
+ toReturn=mAutoCorrects[listName];
+ }
+ return toReturn;
+}
+std::string AutoCorrect::replaceWord(std::string currentWord)
+{
+ static LLCachedControl<bool> doAnything(gSavedSettings, "EnableAutoCorrect");
+ if(!(doAnything))return currentWord;
+ //loop through priorities
+ for(int currentPriority = 10;currentPriority>=0;currentPriority--)
+ {
+ LLSD::map_const_iterator loc_it = mAutoCorrects.beginMap();
+ LLSD::map_const_iterator loc_end = mAutoCorrects.endMap();
+ for (; loc_it != loc_end; ++loc_it)
+ {
+ const std::string& location = (*loc_it).first;
+ //llinfos << "location is "<<location.c_str() << " word is "<<currentWord.c_str()<<llendl;
+ const LLSD& loc_map = (*loc_it).second;
+ if(loc_map["priority"].asInteger()==currentPriority)
+ {
+ if(!loc_map["wordStyle"].asBoolean())
+ {
+ //this means look for partial matches instead of a full word
+ if(loc_map["enabled"].asBoolean())
+ {
+ LLSD::map_const_iterator inner_it = loc_map["data"].beginMap();
+ LLSD::map_const_iterator inner_end = loc_map["data"].endMap();
+ for (; inner_it != inner_end; ++inner_it)
+ {
+ const std::string& wrong = (*inner_it).first;
+ const std::string& right = (*inner_it).second;
+ int location = currentWord.find(wrong);
+ if(location != std::string::npos)
+ {
+ currentWord=currentWord.replace(location,wrong.length(),right);
+ }
+ }
+ }
+
+ }else
+ if((loc_map["data"].has(currentWord))&&(loc_map["enabled"].asBoolean()))
+ {
+ std::string replacement = loc_map["data"][currentWord];
+ if(loc_map["announce"].asBoolean())
+ {
+ LLSD args;
+ //"[Before]" has been auto replaced by "[Replacement]"
+ // based on your [ListName] list.
+ args["BEFORE"] = currentWord;
+ args["LISTNAME"]=location;
+ args["REPLACEMENT"]=replacement;
+ LLNotificationsUtil::add("AutoReplace",args);
+ }
+ gSavedSettings.setS32("AutoCorrectCount",gSavedSettings.getS32("AutoCorrectCount")+1);
+ llinfos << "found a word in list " << location.c_str() << " and it will replace " << currentWord.c_str() << " => " << replacement.c_str() << llendl;
+ return replacement;
+ }
+ }
+ }
+ }
+ return currentWord;
+}
+std::string AutoCorrect::replaceWords(std::string words)
+{
+ static LLCachedControl<bool> doAnything(gSavedSettings, "EnableAutoCorrect");
+ if(!(doAnything))return words;
+ //TODO update this function to use the "wordStyle" thing,
+ //but so far this function is never used, so later
+
+ boost_tokenizer tokens(words, boost::char_separator<char>(" "));
+ for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+ {
+ std::string currentWord(*token_iter);
+ LLSD::map_const_iterator loc_it = mAutoCorrects.beginMap();
+ LLSD::map_const_iterator loc_end = mAutoCorrects.endMap();
+ for (; loc_it != loc_end; ++loc_it)
+ {
+ const std::string& location = (*loc_it).first;
+ //llinfos << "location is "<<location.c_str() << " word is "<<currentWord.c_str()<<llendl;
+ const LLSD& loc_map = (*loc_it).second;
+ if((loc_map["data"].has(currentWord))&&(loc_map["enabled"].asBoolean()))
+ {
+ std::string replacement = loc_map["data"][currentWord];
+ if(loc_map["announce"].asBoolean())
+ {
+ LLSD args;
+ //"[Before]" has been auto replaced by "[Replacement]"
+ // based on your [ListName] list.
+ args["BEFORE"] = currentWord;
+ args["LISTNAME"]=location;
+ args["REPLACEMENT"]=replacement;
+ LLNotificationsUtil::add("AutoReplace",args);
+ }
+ llinfos << "found a word in list " << location.c_str() << " and it will replace " << currentWord.c_str() << " => " << replacement.c_str() << llendl;
+ int wordStart = words.find(currentWord);
+ words.replace(wordStart,currentWord.length(),replacement);
+ return replaceWords(words);//lol recursion!
+ }
+ }
+ }
+ return words;
+}
+BOOL AutoCorrect::addEntryToList(std::string wrong, std::string right, std::string listName)
+{
+ // *HACK: Make sure the "Custom" list exists, because the design of this
+ // system prevents us from updating it by changing the original file...
+ if(mAutoCorrects.has(listName))
+ {
+ mAutoCorrects[listName]["data"][wrong]=right;
+ return TRUE;
+ }
+ else if(listName == "Custom")
+ {
+ mAutoCorrects[listName]["announce"] = 0;
+ mAutoCorrects[listName]["author"] = "You";
+ mAutoCorrects[listName]["data"][wrong] = right;
+ mAutoCorrects[listName]["enabled"] = 1;
+ mAutoCorrects[listName]["priority"] = 10;
+ mAutoCorrects[listName]["wordStyle"] = 1;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+BOOL AutoCorrect::removeEntryFromList(std::string wrong, std::string listName)
+{
+ if(mAutoCorrects.has(listName))
+ {
+ if(mAutoCorrects[listName]["data"].has(wrong))
+ {
+ mAutoCorrects[listName]["data"].erase(wrong);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+LLSD AutoCorrect::getExampleLLSD()
+{
+ LLSD toReturn;
+
+ LLSD listone;
+ LLSD listtwo;
+
+ LLSD itemOne;
+ itemOne["wrong"]="wrong1";
+ itemOne["right"]="right1";
+ listone[0]=itemOne;
+
+ LLSD itemTwo;
+ itemTwo["wrong"]="wrong2";
+ itemTwo["right"]="right2";
+ listone[1]=itemTwo;
+
+ toReturn["listOne"]=listone;
+
+
+ itemOne["wrong"]="secondwrong1";
+ itemOne["right"]="secondright1";
+ listone[0]=itemOne;
+
+ itemTwo["wrong"]="secondwrong2";
+ itemTwo["right"]="secondright2";
+ listone[1]=itemTwo;
+
+ toReturn["listTwo"]=listone;
+
+ return toReturn;
+}
+