Commits

Scott Lawrence committed a9e2fae Merge

merge dictionary import

  • Participants
  • Parent commits e1d4a94, c8e09e8

Comments (0)

Files changed (10)

indra/llui/llspellcheck.cpp

 }
 
 // static
-const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name)
+const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language)
 {
 	for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
 	{
 		const LLSD& dict_entry = *it;
-		if (dict_name == dict_entry["language"].asString())
+		if (dict_language == dict_entry["language"].asString())
 			return dict_entry;
 	}
 	return LLSD();
 }
 
 // static
+void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
+{
+	const std::string dict_language = dict_info["language"].asString();
+	if (dict_language.empty())
+		return;
+
+	for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
+	{
+		LLSD& dict_entry = *it;
+		if (dict_language == dict_entry["language"].asString())
+		{
+			dict_entry = dict_info;
+			return;
+		}
+	}
+	sDictMap.append(dict_info);
+	return;
+}
+
+// static
 void LLSpellChecker::refreshDictionaryMap()
 {
 	const std::string app_path = getDictionaryAppPath();
 	const std::string user_path = getDictionaryUserPath();
 
 	// Load dictionary information (file name, friendly name, ...)
-	llifstream user_map(user_path + "dictionaries.xml", std::ios::binary);
-	if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_map)) || (0 == sDictMap.size()) )
+	llifstream user_file(user_path + "dictionaries.xml", std::ios::binary);
+	if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) )
 	{
-		llifstream app_map(app_path + "dictionaries.xml", std::ios::binary);
-		if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_map)) || (0 == sDictMap.size()) )
+		llifstream app_file(app_path + "dictionaries.xml", std::ios::binary);
+		if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) )
 			return;
 	}
 
+	// Load user installed dictionary information
+	llifstream custom_file(user_path + "user_dictionaries.xml", std::ios::binary);
+	if (custom_file.is_open())
+	{
+		LLSD custom_dict_map;
+		LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file);
+		for (LLSD::array_const_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it)
+			setDictionaryData(*it);
+		custom_file.close();
+	}
+
 	// Look for installed dictionaries
 	std::string tmp_app_path, tmp_user_path;
 	for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
 		sdDict["has_custom"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_CUSTOM_SUFFIX + ".dic"));
 		sdDict["has_ignore"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_IGNORE_SUFFIX + ".dic"));
 	}
+
+	sSettingsChangeSignal();
 }
 
 void LLSpellChecker::addToCustomDictionary(const std::string& word)

indra/llui/llspellcheck.h

 
 	static const std::string getDictionaryAppPath();
 	static const std::string getDictionaryUserPath();
-	static const LLSD		 getDictionaryData(const std::string& dict_name);
+	static const LLSD		 getDictionaryData(const std::string& dict_language);
 	static const LLSD&		 getDictionaryMap() { return sDictMap; }
 	static bool				 getUseSpellCheck();
 	static void				 refreshDictionaryMap();
 	static void				 setUseSpellCheck(const std::string& dict_name);
+protected:
+	static void				 setDictionaryData(const LLSD& dict_info);
 
+public:
 	typedef boost::signals2::signal<void()> settings_change_signal_t;
 	static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb);
 protected:

indra/newview/llfilepicker.cpp

 #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
 #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
 #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
+#define DICTIONARY_FILTER L"Dictionary files (*.dic)\0*.dic\0"
 #endif
 
 //
 		mOFN.lpstrFilter = SCRIPT_FILTER \
 			L"\0";
 		break;
+	case FFLOAD_DICTIONARY:
+		mOFN.lpstrFilter = DICTIONARY_FILTER \
+			L"\0";
+		break;
 	default:
 		res = FALSE;
 		break;
 								result = false;
 							}
 						}
+						else if (filter == FFLOAD_DICTIONARY)
+						{
+							if (fileInfo.filetype != 'DIC ' &&
+								(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dic"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) )
+							{
+								result = false;
+							}
+						}
 						
 						if (fileInfo.extension)
 						{
 							LLTrans::getString("script_files") + " (*.lsl)");
 }
 
+static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)
+{
+	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain",
+							LLTrans::getString("dictionary_files") + " (*.dic)");
+}
+
 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
 {
 	BOOL rtn = FALSE;
 		case FFLOAD_SCRIPT:
 			filtername = add_script_filter_to_gtkchooser(picker);
 			break;
+		case FFLOAD_DICTIONARY:
+			filtername = add_dictionary_filter_to_gtkchooser(picker);
+			break;
 		default:;
 			break;
 		}

indra/newview/llfilepicker.h

 		FFLOAD_MODEL = 9,
 		FFLOAD_COLLADA = 10,
 		FFLOAD_SCRIPT = 11,
+		FFLOAD_DICTIONARY = 12
 	};
 
 	enum ESaveFilter

indra/newview/llfloaterspellchecksettings.cpp

 #include "llviewerprecompiledheaders.h"
 
 #include "llcombobox.h"
+#include "llfilepicker.h"
+#include "llfloaterreg.h"
 #include "llfloaterspellchecksettings.h"
 #include "llscrolllistctrl.h"
+#include "llsdserialize.h"
 #include "llspellcheck.h"
 #include "llviewercontrol.h"
 
 #include <boost/algorithm/string.hpp>
 
+///----------------------------------------------------------------------------
+/// Class LLFloaterSpellCheckerSettings
+///----------------------------------------------------------------------------
 LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key)
 	: LLFloater(key)
 {
 BOOL LLFloaterSpellCheckerSettings::postBuild(void)
 {
 	gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
+	LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this));
+	getChild<LLUICtrl>("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this));
 	getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
-	getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_active_list", "spellcheck_available_list"));
-	getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_available_list", "spellcheck_active_list"));
-	getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onOK, this));
-	getChild<LLUICtrl>("spellcheck_cancel")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onCancel, this));
+	getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list"));
+	getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_available_list", "spellcheck_active_list"));
+	getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnOK, this));
+	getChild<LLUICtrl>("spellcheck_cancel")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnCancel, this));
 
 	return true;
 }
 
-void LLFloaterSpellCheckerSettings::onCancel()
+void LLFloaterSpellCheckerSettings::onBtnCancel()
 {
 	closeFloater(false);
 }
 
-void LLFloaterSpellCheckerSettings::onClickDictMove(const std::string& from, const std::string& to)
+void LLFloaterSpellCheckerSettings::onBtnImport()
+{
+	LLFloaterReg::showInstance("prefs_spellchecker_import");
+}
+
+void LLFloaterSpellCheckerSettings::onBtnMove(const std::string& from, const std::string& to)
 {
 	LLScrollListCtrl* from_ctrl = findChild<LLScrollListCtrl>(from);
 	LLScrollListCtrl* to_ctrl = findChild<LLScrollListCtrl>(to);
 	from_ctrl->deleteSelectedItems();
 }
 
-void LLFloaterSpellCheckerSettings::onOK()
+void LLFloaterSpellCheckerSettings::onBtnOK()
 {
 	std::list<std::string> list_dict;
 
 	refreshDictionaryLists(true);
 }
 
+void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange()
+{
+	refreshDictionaryLists(true);
+}
+
 void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
 {
 	bool enabled = gSavedSettings.getBOOL("SpellCheck");
 		}
 	}
 }
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterSpellCheckerImport
+///----------------------------------------------------------------------------
+LLFloaterSpellCheckerImport::LLFloaterSpellCheckerImport(const LLSD& key)
+	: LLFloater(key)
+{
+}
+
+BOOL LLFloaterSpellCheckerImport::postBuild(void)
+{
+	getChild<LLUICtrl>("dictionary_path_browse")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnBrowse, this));
+	getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnOK, this));
+	getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnCancel, this));
+
+	return true;
+}
+
+void LLFloaterSpellCheckerImport::onBtnBrowse()
+{
+	LLFilePicker& file_picker = LLFilePicker::instance();
+	if (!file_picker.getOpenFile(LLFilePicker::FFLOAD_DICTIONARY))
+	{
+		return;
+	}
+
+	const std::string filepath = file_picker.getFirstFile();
+	getChild<LLUICtrl>("dictionary_path")->setValue(filepath);
+	
+	mDictionaryDir = gDirUtilp->getDirName(filepath);
+	mDictionaryBasename = gDirUtilp->getBaseFileName(filepath, true);
+	getChild<LLUICtrl>("dictionary_name")->setValue(mDictionaryBasename);
+}
+
+void LLFloaterSpellCheckerImport::onBtnCancel()
+{
+	closeFloater(false);
+}
+
+void LLFloaterSpellCheckerImport::onBtnOK()
+{
+	const std::string dict_dic = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".dic";
+	const std::string dict_aff = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".aff";
+	std::string dict_language = getChild<LLUICtrl>("dictionary_language")->getValue().asString();
+	LLStringUtil::trim(dict_language);
+	if ( (dict_language.empty()) || (!gDirUtilp->fileExists(dict_dic)) || 
+		 (mDictionaryDir.empty()) || (mDictionaryBasename.empty()) )
+	{
+		return;
+	}
+
+	LLSD custom_dict_info;
+	custom_dict_info["is_primary"] = (bool)gDirUtilp->fileExists(dict_aff);
+	custom_dict_info["name"] = mDictionaryBasename;
+	custom_dict_info["language"] = dict_language;
+
+	LLSD custom_dict_map;
+	llifstream custom_file_in(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml");
+	if (custom_file_in.is_open())
+	{
+		LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file_in);
+		custom_file_in.close();
+	}
+	
+	LLSD::array_iterator it = custom_dict_map.beginArray();
+	for (; it != custom_dict_map.endArray(); ++it)
+	{
+		LLSD& dict_info = *it;
+		if (dict_info["name"].asString() == mDictionaryBasename)
+		{
+			dict_info = custom_dict_info;
+			break;
+		}
+	}
+	if (custom_dict_map.endArray() == it)
+	{
+		custom_dict_map.append(custom_dict_info);
+	}
+
+	llofstream custom_file_out(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml", std::ios::trunc);
+	if (custom_file_out.is_open())
+	{
+		LLSDSerialize::toPrettyXML(custom_dict_map, custom_file_out);
+		custom_file_out.close();
+	}
+
+	LLFile::rename(dict_dic, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic");
+	if (gDirUtilp->fileExists(dict_aff))
+	{
+		LLFile::rename(dict_aff, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff");
+	}
+	LLSpellChecker::refreshDictionaryMap();
+
+	closeFloater(false);
+}

indra/newview/llfloaterspellchecksettings.h

 	/*virtual*/ void onOpen(const LLSD& key);
 
 protected:
-	void onCancel();
-	void onClickDictMove(const std::string& from, const std::string& to);
-	void onOK();
-	void onSave();
+	void onBtnCancel();
+	void onBtnImport();
+	void onBtnMove(const std::string& from, const std::string& to);
+	void onBtnOK();
+	void onSpellCheckSettingsChange();
 	void refreshDictionaryLists(bool from_settings);
 };
 
+class LLFloaterSpellCheckerImport : public LLFloater
+{
+public:
+	LLFloaterSpellCheckerImport(const LLSD& key);
+
+	/*virtual*/ BOOL postBuild();
+
+protected:
+	void onBtnBrowse();
+	void onBtnCancel();
+	void onBtnOK();
+
+	std::string mDictionaryDir;
+	std::string mDictionaryBasename;
+};
+
 #endif  // LLFLOATERSPELLCHECKERSETTINGS_H

indra/newview/llviewerfloaterreg.cpp

 	LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
 	LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
 	LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);
+	LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>);
 	LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>);
 	LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>);
 	LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>);

indra/newview/skins/default/xui/en/floater_spellcheck.xml

    top_pad="-15"
    width="175"
   />
+  <button
+   follows="left|top"
+   height="23"
+   label="Import"
+   label_selected="Import"
+   layout="topleft"
+   left_pad="5"
+   name="spellcheck_import_btn"
+   top_delta="0"
+   width="75" />
   <text
    enabled_control="SpellCheck"
    follows="top|left"

indra/newview/skins/default/xui/en/floater_spellcheck_import.xml

+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ border="true"
+ can_close="true"
+ can_minimize="true"
+ bottom="275"
+ left="300"
+ can_resize="false"
+ height="140"
+ width="400"
+ name="spellcheck_import"
+ title="Import Dictionary">
+  <text
+   follows="top|left"
+   height="16"
+   layout="topleft"
+   left="25"
+   top="15"
+   type="string"
+   width="65">
+   Dictionary:
+  </text>
+  <line_editor
+   enabled="false"
+   follows="left|top"
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   max_length_bytes="255"
+   name="dictionary_path"
+   top_delta="-5"
+   width="200" />
+  <button
+   follows="left|top"
+   height="23"
+   label="Browse"
+   label_selected="Browse"
+   layout="topleft"
+   left_pad="5"
+   name="dictionary_path_browse"
+   top_delta="0"
+   width="75" />
+  <text
+   follows="top|left"
+   height="16"
+   layout="topleft"
+   left="25"
+   top_pad="8"
+   type="string"
+   width="65">
+   Name:
+  </text>
+  <line_editor
+   enabled="false"
+   follows="left|top"
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   max_length_bytes="255"
+   name="dictionary_name"
+   top_delta="-5"
+   width="200" />
+  <text
+   follows="top|left"
+   height="16"
+   layout="topleft"
+   left="25"
+   top_pad="8"
+   type="string"
+   width="65">
+   Language:
+  </text>
+  <line_editor
+   follows="left|top"
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   max_length_bytes="255"
+   name="dictionary_language"
+   top_delta="-5"
+   width="200" />
+  <view_border
+   top_pad="10"
+   left="2"
+   height="0"
+   width="396"
+   follows="left|top"
+   bevel_style="none"
+   border_thickness="1"
+   mouse_opaque="false"
+   name="divisor"/>
+  <button
+   top_pad="10"
+   right="280"
+   height="22"
+   width="90"
+   enabled="true"
+   follows="left|top"
+   mouse_opaque="true"
+   halign="center"
+   scale_image="true"
+   name="ok_btn"
+   label="Import" />
+  <button
+   top_delta="0"
+   right="380"
+   height="22"
+   width="90"
+   enabled="true"
+   follows="left|top"
+   mouse_opaque="true"
+   halign="center"
+   scale_image="true"
+   name="cancel_btn"
+   label="Cancel" />
+</floater>

indra/newview/skins/default/xui/en/strings.xml

 	<string name="load_files">Load Files</string>
 	<string name="choose_the_directory">Choose Directory</string>
 	<string name="script_files">Scripts</string>
+	<string name="dictionary_files">Dictionaries</string>
 
   <!-- LSL Usage Hover Tips -->
   <!-- NOTE: For now these are set as translate="false", until DEV-40761 is implemented (to internationalize the rest of tooltips in the same window).