/** * @file llviewercontrollistener.cpp * @author Brad Kittenbrink * @date 2009-07-09 * @brief Implementation for llviewercontrollistener. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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; * version 2.1 of the License only. * * 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 * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llviewercontrollistener.h" #include "llviewercontrol.h" #include "llcontrol.h" #include "llerror.h" #include "llsdutil.h" #include "stringize.h" #include namespace { LLViewerControlListener sSavedSettingsListener; } // unnamed namespace LLViewerControlListener::LLViewerControlListener() : LLEventAPI("LLViewerControl", "LLViewerControl listener: set, toggle or set default for various controls") { std::ostringstream groupnames; groupnames << "[\"group\"] is one of "; const char* delim = ""; for (const auto& key : LLControlGroup::key_snapshot()) { groupnames << delim << '"' << key << '"'; delim = ", "; } groupnames << '\n'; std::string grouphelp(groupnames.str()); std::string replyhelp("If [\"reply\"] requested, send new [\"value\"] on specified LLEventPump\n"); add("set", std::string("Set [\"group\"] control [\"key\"] to optional value [\"value\"]\n" "If [\"value\"] omitted, set to control's defined default value\n") + grouphelp + replyhelp, &LLViewerControlListener::set, LLSDMap("group", LLSD())("key", LLSD())); add("toggle", std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, &LLViewerControlListener::toggle, LLSDMap("group", LLSD())("key", LLSD())); add("get", std::string("Query [\"group\"] control [\"key\"], replying on LLEventPump [\"reply\"]\n") + grouphelp, &LLViewerControlListener::get, LLSDMap("group", LLSD())("key", LLSD())("reply", LLSD())); add("groups", "Send on LLEventPump [\"reply\"] an array [\"groups\"] of valid group names", &LLViewerControlListener::groups, LLSDMap("reply", LLSD())); add("vars", std::string("For [\"group\"], send on LLEventPump [\"reply\"] an array [\"vars\"],\n" "each of whose entries looks like:\n" " [\"name\"], [\"type\"], [\"value\"], [\"comment\"]\n") + grouphelp, &LLViewerControlListener::vars, LLSDMap("group", LLSD())("reply", LLSD())); } struct Info { Info(const LLSD& request): response(LLSD(), request), groupname(request["group"]), group(LLControlGroup::getInstance(groupname)), key(request["key"]), control(NULL) { if (! group) { response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); return; } control = group->getControl(key); if (! control) { response.error(STRINGIZE("In group '" << groupname << "', unrecognized control key '" << key << "'")); } } ~Info() { // If in fact the request passed to our constructor names a valid // group and key, grab the final value of the indicated control and // stuff it in our response. Since this outer destructor runs before // the contained Response destructor, this data will go into the // response we send. if (control) { response["name"] = control->getName(); response["type"] = LLControlGroup::typeEnumToString(control->type()); response["value"] = control->get(); response["comment"] = control->getComment(); } } LLEventAPI::Response response; std::string groupname; LLControlGroup::ptr_t group; std::string key; LLControlVariable* control; }; //static void LLViewerControlListener::set(LLSD const & request) { Info info(request); if (! info.control) return; if (request.has("value")) { LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL; info.control->setValue(request["value"], false); } else { info.control->resetToDefault(); } } //static void LLViewerControlListener::toggle(LLSD const & request) { Info info(request); if (! info.control) return; if (info.control->isType(TYPE_BOOLEAN)) { bool value = !info.control->get().asBoolean(); LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL; info.control->set(value, false); } else { info.response.error(STRINGIZE("toggle of non-boolean '" << info.groupname << "' control '" << info.key << "', type is " << LLControlGroup::typeEnumToString(info.control->type()))); } } void LLViewerControlListener::get(LLSD const & request) { // The Info constructor and destructor actually do all the work here. Info info(request); } void LLViewerControlListener::groups(LLSD const & request) { // No Info, we're not looking up either a group or a control name. Response response(LLSD(), request); for (const auto& key : LLControlGroup::key_snapshot()) { response["groups"].append(key); } } struct CollectVars: public LLControlGroup::ApplyFunctor { CollectVars(LLControlGroup::ptr_t g): mGroup(g) {} virtual void apply(const std::string& name, LLControlVariable* control) { vars.append(LLSDMap ("name", name) ("type", LLControlGroup::typeEnumToString(control->type())) ("value", control->get()) ("comment", control->getComment())); } LLControlGroup::ptr_t mGroup; LLSD vars; }; void LLViewerControlListener::vars(LLSD const & request) { // This method doesn't use Info, because we're not looking up a specific // control name. Response response(LLSD(), request); std::string groupname(request["group"]); auto group(LLControlGroup::getInstance(groupname)); if (! group) { return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); } CollectVars collector(group); group->applyToAll(&collector); response["vars"] = collector.vars; }