/** * @file llfloaterautoreplacesettings.cpp * @brief Auto Replace List floater * * $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 "llfloaterautoreplacesettings.h" #include "llagentdata.h" #include "llcommandhandler.h" #include "llfloater.h" #include "lluictrlfactory.h" #include "llagent.h" #include "llpanel.h" #include "llbutton.h" #include "llcolorswatch.h" #include "llcombobox.h" #include "llview.h" #include "llbufferstream.h" #include "llcheckboxctrl.h" #include "llviewercontrol.h" #include "llui.h" #include "llcontrol.h" #include "llscrollingpanellist.h" #include "llautoreplace.h" #include "llfilepicker.h" #include "llfile.h" #include "llsdserialize.h" #include "llsdutil.h" #include "llchat.h" #include "llinventorymodel.h" #include "llhost.h" #include "llassetstorage.h" #include "roles_constants.h" #include "llviewermenufile.h" // LLFilePickerReplyThread #include "llviewertexteditor.h" #include #include #include "llfloaterreg.h" #include "llinspecttoast.h" #include "llnotificationhandler.h" #include "llnotificationmanager.h" #include "llnotificationsutil.h" LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key) : LLFloater(key) , mSelectedListName("") , mListNames(NULL) , mReplacementsList(NULL) , mKeyword(NULL) , mPreviousKeyword("") , mReplacement(NULL) { } void LLFloaterAutoReplaceSettings::onClose(bool app_quitting) { cleanUp(); } bool LLFloaterAutoReplaceSettings::postBuild(void) { // get copies of the current settings that we will operate on mEnabled = gSavedSettings.getBOOL("AutoReplace"); LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL; mSettings = LLAutoReplace::getInstance()->getSettings(); // global checkbox for whether or not autoreplace is active LLUICtrl* enabledCheckbox = getChild("autoreplace_enable"); enabledCheckbox->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onAutoReplaceToggled, this)); enabledCheckbox->setValue(LLSD(mEnabled)); // top row list creation and deletion getChild("autoreplace_import_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onImportList,this)); getChild("autoreplace_export_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onExportList,this)); getChild("autoreplace_new_list")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onNewList,this)); getChild("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteList,this)); // the list of keyword->replacement lists mListNames = getChild("autoreplace_list_name"); mListNames->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectList, this)); mListNames->setCommitOnSelectionChange(true); // list ordering getChild("autoreplace_list_up")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onListUp,this)); getChild("autoreplace_list_down")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onListDown,this)); // keyword->replacement entry add / delete getChild("autoreplace_add_entry")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onAddEntry,this)); getChild("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteEntry,this)); // entry edits mKeyword = getChild("autoreplace_keyword"); mReplacement = getChild("autoreplace_replacement"); getChild("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveEntry, this)); // dialog termination ( Save Changes / Cancel ) getChild("autoreplace_save_changes")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveChanges, this)); getChild("autoreplace_cancel")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onCancel, this)); // the list of keyword->replacement pairs mReplacementsList = getChild("autoreplace_list_replacements"); mReplacementsList->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectEntry, this)); mReplacementsList->setCommitOnSelectionChange(true); center(); mSelectedListName.clear(); updateListNames(); updateListNamesControls(); updateReplacementsList(); return true; } void LLFloaterAutoReplaceSettings::updateListNames() { mListNames->deleteAllItems(); // start from scratch LLSD listNames = mSettings.getListNames(); // Array of Strings for ( LLSD::array_const_iterator entry = listNames.beginArray(), end = listNames.endArray(); entry != end; ++entry ) { const std::string& listName = entry->asString(); mListNames->addSimpleElement(listName); } if (!mSelectedListName.empty()) { mListNames->setSelectedByValue( LLSD(mSelectedListName), true ); } } void LLFloaterAutoReplaceSettings::updateListNamesControls() { if ( mSelectedListName.empty() ) { // There is no selected list // Disable all controls that operate on the selected list getChild("autoreplace_export_list")->setEnabled(false); getChild("autoreplace_delete_list")->setEnabled(false); getChild("autoreplace_list_up")->setEnabled(false); getChild("autoreplace_list_down")->setEnabled(false); mReplacementsList->deleteAllItems(); } else { // Enable the controls that operate on the selected list getChild("autoreplace_export_list")->setEnabled(true); getChild("autoreplace_delete_list")->setEnabled(true); getChild("autoreplace_list_up")->setEnabled(!selectedListIsFirst()); getChild("autoreplace_list_down")->setEnabled(!selectedListIsLast()); } } void LLFloaterAutoReplaceSettings::onSelectList() { std::string previousSelectedListName = mSelectedListName; // only one selection allowed LLSD selected = mListNames->getSelectedValue(); if (selected.isDefined()) { mSelectedListName = selected.asString(); LL_DEBUGS("AutoReplace")<<"selected list '"<getSelectedValue(); if (selectedRow.isDefined()) { mPreviousKeyword = selectedRow.asString(); LL_DEBUGS("AutoReplace")<<"selected entry '"<setValue(selectedRow); std::string replacement = mSettings.replacementFor(mPreviousKeyword, mSelectedListName ); mReplacement->setValue(replacement); enableReplacementEntry(); mReplacement->setFocus(true); } else { // no entry selection, so the entry panel should be off disableReplacementEntry(); LL_DEBUGS("AutoReplace")<<"no row selected"<deleteAllItems(); if ( mSelectedListName.empty() ) { mReplacementsList->setEnabled(false); getChild("autoreplace_add_entry")->setEnabled(false); disableReplacementEntry(); } else { // Populate the keyword->replacement list from the selected list const LLSD* mappings = mSettings.getListEntries(mSelectedListName); for ( LLSD::map_const_iterator entry = mappings->beginMap(), end = mappings->endMap(); entry != end; entry++ ) { LLSD row; row["id"] = entry->first; row["columns"][0]["column"] = "keyword"; row["columns"][0]["value"] = entry->first; row["columns"][1]["column"] = "replacement"; row["columns"][1]["value"] = entry->second; mReplacementsList->addElement(row, ADD_BOTTOM); } mReplacementsList->deselectAllItems(false /* don't call commit */); mReplacementsList->setEnabled(true); getChild("autoreplace_add_entry")->setEnabled(true); disableReplacementEntry(); } } void LLFloaterAutoReplaceSettings::enableReplacementEntry() { LL_DEBUGS("AutoReplace")<setEnabled(true); mReplacement->setEnabled(true); getChild("autoreplace_save_entry")->setEnabled(true); getChild("autoreplace_delete_entry")->setEnabled(true); } void LLFloaterAutoReplaceSettings::disableReplacementEntry() { LL_DEBUGS("AutoReplace")<clear(); mKeyword->setEnabled(false); mReplacement->clear(); mReplacement->setEnabled(false); getChild("autoreplace_save_entry")->setEnabled(false); getChild("autoreplace_delete_entry")->setEnabled(false); } // called when the global settings checkbox is changed void LLFloaterAutoReplaceSettings::onAutoReplaceToggled() { // set our local copy of the flag, copied to the global preference in onOk mEnabled = childGetValue("autoreplace_enable").asBoolean(); LL_DEBUGS("AutoReplace")<< "autoreplace_enable " << ( mEnabled ? "on" : "off" ) << LL_ENDL; } // called when the List Up button is pressed void LLFloaterAutoReplaceSettings::onListUp() { S32 selectedRow = mListNames->getFirstSelectedIndex(); LLSD selectedName = mListNames->getSelectedValue().asString(); if ( mSettings.increaseListPriority(selectedName) ) { updateListNames(); updateListNamesControls(); } else { LL_WARNS("AutoReplace") << "invalid row ("<getFirstSelectedIndex(); std::string selectedName = mListNames->getSelectedValue().asString(); if ( mSettings.decreaseListPriority(selectedName) ) { updateListNames(); updateListNamesControls(); } else { LL_WARNS("AutoReplace") << "invalid row ("<getSelectedValue(); if (selectedRow.isDefined()) { std::string keyword = selectedRow.asString(); mReplacementsList->deleteSelectedItems(); // delete from the control mSettings.removeEntryFromList(keyword, mSelectedListName); // delete from the local settings copy disableReplacementEntry(); // no selection active, so turn off the buttons } } // called when the Import List button is pressed void LLFloaterAutoReplaceSettings::onImportList() { LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::loadListFromFile, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterAutoReplaceSettings::loadListFromFile(const std::vector& filenames) { llifstream file; file.open(filenames[0].c_str()); LLSD newList; if (file.is_open()) { LLSDSerialize::fromXMLDocument(newList, file); } file.close(); switch ( mSettings.addList(newList) ) { case LLAutoReplaceSettings::AddListOk: mSelectedListName = LLAutoReplaceSettings::getListName(newList); updateListNames(); updateListNamesControls(); updateReplacementsList(); break; case LLAutoReplaceSettings::AddListDuplicateName: { std::string newName = LLAutoReplaceSettings::getListName(newList); LL_WARNS("AutoReplace")<<"name '"<getSelectedValue().asString(); if ( ! listName.empty() ) { if ( mSettings.removeReplacementList(listName) ) { LL_INFOS("AutoReplace")<<"deleted list '"<deleteSelectedItems(); // remove from the scrolling list mSelectedListName.clear(); updateListNames(); updateListNamesControls(); updateReplacementsList(); } else { LL_WARNS("AutoReplace")<<"failed to delete list '"<getFirstSelected()->getColumn(0)->getValue().asString(); std::string listFileName = listName + ".xml"; LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::saveListToFile, this, _1, listName), LLFilePicker::FFSAVE_XML, listFileName); } void LLFloaterAutoReplaceSettings::saveListToFile(const std::vector& filenames, std::string listName) { llofstream file; const LLSD* list = mSettings.exportList(listName); file.open(filenames[0].c_str()); LLSDSerialize::toPrettyXML(*list, file); file.close(); } void LLFloaterAutoReplaceSettings::onAddEntry() { mPreviousKeyword.clear(); mReplacementsList->deselectAllItems(false /* don't call commit */); mKeyword->clear(); mReplacement->clear(); enableReplacementEntry(); mKeyword->setFocus(true); } void LLFloaterAutoReplaceSettings::onSaveEntry() { LL_DEBUGS("AutoReplace")<<"called"<getWText(); LLWString replacement = mReplacement->getWText(); if ( mSettings.addEntryToList(keyword, replacement, mSelectedListName) ) { // insert the new keyword->replacement pair LL_INFOS("AutoReplace") << "list '" << mSelectedListName << "' " << "added '" << wstring_to_utf8str(keyword) << "' -> '" << wstring_to_utf8str(replacement) << "'" << LL_ENDL; updateReplacementsList(); } else { LLNotificationsUtil::add("InvalidAutoReplaceEntry"); LL_WARNS("AutoReplace")<<"invalid entry " << "keyword '" << wstring_to_utf8str(keyword) << "' replacement '" << wstring_to_utf8str(replacement) << "'" << LL_ENDL; } } void LLFloaterAutoReplaceSettings::onCancel() { cleanUp(); closeFloater(false /* not quitting */); } void LLFloaterAutoReplaceSettings::onSaveChanges() { // put our local copy of the settings into the active copy LLAutoReplace::getInstance()->setSettings( mSettings ); // save our local copy of the global feature enable/disable value gSavedSettings.setBOOL("AutoReplace", mEnabled); cleanUp(); closeFloater(false /* not quitting */); } void LLFloaterAutoReplaceSettings::cleanUp() { } bool LLFloaterAutoReplaceSettings::selectedListIsFirst() { bool isFirst = false; if (!mSelectedListName.empty()) { LLSD lists = mSettings.getListNames(); // an Array of Strings LLSD first = lists.get(0); if ( first.isString() && first.asString() == mSelectedListName ) { isFirst = true; } } return isFirst; } bool LLFloaterAutoReplaceSettings::selectedListIsLast() { bool isLast = false; if (!mSelectedListName.empty()) { LLSD last; LLSD lists = mSettings.getListNames(); // an Array of Strings for ( LLSD::array_const_iterator list = lists.beginArray(), listEnd = lists.endArray(); list != listEnd; list++ ) { last = *list; } if ( last.isString() && last.asString() == mSelectedListName ) { isLast = true; } } return isLast; } /* TBD mOldText = getChild("autoreplace_old_text"); mNewText = getChild("autoreplace_new_text"); */